为什么 class 具有其元 class 的属性?
Why does a class have the attributes of its metaclass?
我有一个像这样的 metaclass
class UpperMeta(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
def echo(cls):
return 'echo'
class B(object):
__metaclass__ = UpperMeta
assert hasattr(B, 'echo')
assert B.echo() == 'echo'
assert not issubclass(B, UpperMeta)
我的问题是:
- 为什么 class
B
有一个 echo
方法?如果 B
不是 UpperMeta
的子 class,它不应该有 echo
属性?
- class 从元class 中获得了哪些属性?
class
对象 B
属于 type
UpperMeta
。
这导致 UpperMeta
的所有 class 方法在 class B
上可用。该属性不在 class B
上,而是从 B
的 class 代理(B
是 class,不是实例B
)
>>> print dir(B)
# General lack of echo()
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
它在这里:
>>> print dir(B.__class__)
['__abstractmethods__', '__base__', ..., 'echo', 'mro']
The default behavior for attribute access is to get, set, or delete
the attribute from an object’s dictionary. For instance, a.x has a
lookup chain starting with a.dict['x'], then
type(a).dict['x'], and continuing through the base classes of
type(a) excluding metaclasses.
结尾有点混乱"...不包括元classes..",这实际上意味着元classes类型(a),因此说如果你的元class UpperMeta
有一个元class TopMeta
和TopMeta
定义sos()
,那个不会被查找:
class TopMeta(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(TopMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
def sos(cls):
return 'sos'
class UpperMeta(type):
__metaclass__ = TopMeta
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
class B(object):
__metaclass__ = UpperMeta
assert not hasattr(B, 'sos')
唯一正确解释 metaclasses 的演讲:David Beazley - Python 3 Metaprogramming。您只有前 80 分钟左右的时间。
why class B have method of echo, B is not subclass of UpperMeta, it
should not have echo attr?
如果您查看 What is a metaclass in Python? or Customizing class creation,您会看到(引自 python 文档)
if __metaclass__
is defined then the callable assigned to it will be
called instead of type().
is essentially a dynamic form of the class statement. The name string
is the class name and becomes the __name__
attribute; the bases
tuple itemizes the base classes and becomes the __bases__
attribute;
and the dict dictionary is the namespace containing definitions for
class body and becomes the __dict__
attribute. For example, the
following two statements create identical type objects:
>>> class X(object):
... a = 1
...
>>> X = type('X', (object,), dict(a=1))
这是,它是"just like" class扩展名。这也回答了
What attribute class get from metaclass?
几乎所有内容。
也请be aware that
If you wonder whether you need them, you don't (the people who
actually need them know with certainty that they need them, and don't
need an explanation about why).
然而在,他说
Q: Can you have too much of [metaprogramming]
A: No
所以他觉得学习很重要
我有一个像这样的 metaclass
class UpperMeta(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
def echo(cls):
return 'echo'
class B(object):
__metaclass__ = UpperMeta
assert hasattr(B, 'echo')
assert B.echo() == 'echo'
assert not issubclass(B, UpperMeta)
我的问题是:
- 为什么 class
B
有一个echo
方法?如果B
不是UpperMeta
的子 class,它不应该有echo
属性? - class 从元class 中获得了哪些属性?
class
对象 B
属于 type
UpperMeta
。
这导致 UpperMeta
的所有 class 方法在 class B
上可用。该属性不在 class B
上,而是从 B
的 class 代理(B
是 class,不是实例B
)
>>> print dir(B)
# General lack of echo()
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
它在这里:
>>> print dir(B.__class__)
['__abstractmethods__', '__base__', ..., 'echo', 'mro']
The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with a.dict['x'], then type(a).dict['x'], and continuing through the base classes of type(a) excluding metaclasses.
结尾有点混乱"...不包括元classes..",这实际上意味着元classes类型(a),因此说如果你的元class UpperMeta
有一个元class TopMeta
和TopMeta
定义sos()
,那个不会被查找:
class TopMeta(type):
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(TopMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
def sos(cls):
return 'sos'
class UpperMeta(type):
__metaclass__ = TopMeta
def __new__(cls, clsname, bases, dct):
uppercase_attr = {}
for name, val in dct.items():
if not name.startswith('__'):
uppercase_attr[name.upper()] = val
else:
uppercase_attr[name] = val
return super(UpperMeta, cls).__new__(cls, clsname, bases, uppercase_attr)
class B(object):
__metaclass__ = UpperMeta
assert not hasattr(B, 'sos')
唯一正确解释 metaclasses 的演讲:David Beazley - Python 3 Metaprogramming。您只有前 80 分钟左右的时间。
why class B have method of echo, B is not subclass of UpperMeta, it should not have echo attr?
如果您查看 What is a metaclass in Python? or Customizing class creation,您会看到(引自 python 文档)
if
__metaclass__
is defined then the callable assigned to it will be called instead of type().
is essentially a dynamic form of the class statement. The name string is the class name and becomes the
__name__
attribute; the bases tuple itemizes the base classes and becomes the__bases__
attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the__dict__
attribute. For example, the following two statements create identical type objects:>>> class X(object): ... a = 1 ... >>> X = type('X', (object,), dict(a=1))
这是,它是"just like" class扩展名。这也回答了
What attribute class get from metaclass?
几乎所有内容。
也请be aware that
If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
然而在
Q: Can you have too much of [metaprogramming] A: No
所以他觉得学习很重要