关于python:为什么一个类具有其元类的属性?

Why does a class have the attributes of its metaclass?

我有一个像这样的超类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)

我的问题是:

  • 为什么类Becho方法?如果B不是UpperMeta的一个子类,它不应该有echo属性?
  • 类从元类获取哪些属性?

  • why class B have method of echo, B is not subclass of UpperMeta, it
    should not have echo attr?

    如果您看到什么是Python中的元类?或者定制类创建,您会看到(引用自python文档)

    if __metaclass__ is defined then the callable assigned to it will be
    called instead of type().

    埃多克斯1〔14〕

    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:

    1
    2
    3
    4
    >>> class X(object):
    ...     a = 1
    ...
    >>> X = type('X', (object,), dict(a=1))

    这就是"就像"类扩展。这也可以回答

    What attribute class get from metaclass?

    几乎所有的事情。

    请注意:

    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).

    但在@sebastian发布的视频中,他说

    Q: Can you have too much of [metaprogramming]
    A: No

    所以他认为学习很重要。


    class对象BtypeUpperMeta的对象。

    因此,UpperMeta的所有类方法都可以在B类上使用。该属性不在类B上,而是从B的类(B是类,不是B的实例)代理的。

    1
    2
    3
    >>> 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__']

    在这里:

    1
    2
    >>> 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.

    最后,这有点令人困惑"…排除元类….",这实际上意味着类型(A)的元类,因此,如果元类UpperMeta有一个元类TopMeta,而TopMeta定义了sos(),则不会查找该类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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')

    唯一正确解释元类的讨论是:david beazley-python 3元编程。你只有前80分钟左右。