【发布时间】:2021-07-10 07:45:36
【问题描述】:
好的,显然元类中的__new__ 在元类的实例(即类对象)被实例化时运行,因此元类中的__new__ 提供了一个挂钩来在类定义时拦截事件(/运行的代码)(例如验证/执行类属性(如方法等)的规则。
元类中__new__ 的许多在线示例从__new__ 返回类型构造函数的实例,这似乎有点问题,因为这会阻塞__init__ (docs: "如果__new__() 不返回cls 的实例,则不会调用新实例的__init__() 方法")。
在修改元类中 __new__ 的返回值时,我遇到了一些我不完全理解的奇怪案例,例如:
class Meta(type):
def __new__(self, name, bases, attrs):
print("Meta __new__ running!")
# return type(name, bases, attrs) # 1.
# return super().__new__(self, name, bases, attrs) # 2.
# return super().__new__(name, bases, attrs) # 3.
# return super().__new__(type, name, bases, attrs) # 4.
# return self(name, bases, attrs) # 5.
def __init__(self, *args, **kwargs):
print("Meta __init__ running!")
return super().__init__(*args, **kwargs)
class Cls(metaclass=Meta):
pass
- 这在示例中很常见并且通常有效,但会阻止
__init__ - 这有效,
__init__也会触发;但是为什么要将 self 传递给 super() 调用呢? self/cls 不应该用 super() 自动传递吗? - 这会引发一个我无法理解的奇怪错误:TypeError:
type.__new__(X): X is not a type object (str); X是什么? self 不应该自动通过吗? - 3.的错误启发我去玩super()调用的第一个arg,所以我尝试直接传type;这也阻止了
__init__。这里发生了什么? - 只是为了好玩;这会导致 RecursionError
尤其是案例 1. 和 2. 似乎对从绑定到元类的类继承具有相当深远的影响:
class LowerCaseEnforcer(type):
""" Allows only lower case names as class attributes! """
def __new__(self, name, bases, attrs):
for name in attrs:
if name.lower() != name:
raise TypeError(f"Inappropriate method name: {name}")
# return type(name, bases, attrs) # 1.
# return super().__new__(self, name, bases, attrs) # 2.
class Super(metaclass=LowerCaseEnforcer):
pass
class Sub(Super):
def some_method(self):
pass
## this will error in case 2 but not case 1
def Another_method(self):
pass
- 预期行为:元类绑定到超类,而不是子类
- 将超类/和/子类绑定到元类; ?
如果有人能缓慢而友好地解释上述示例中到底发生了什么,我将不胜感激! :D
【问题讨论】: