为什么类具有其元类的属性?

时间:2015-11-02 08:10:45

标签: python subclass metaclass

我有一个像这样的元类

GroupMember

我的问题是:

  1. 为什么课程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) B - 方法?如果echo不是B的子类,则它不应该有UpperMeta attr?
  2. 一个类从元类中获取哪些属性?

2 个答案:

答案 0 :(得分:1)

class对象B属于type UpperMeta

这导致UpperMeta的所有类方法在类B上都可用。该属性不在类B上,而是从B的类中获取代理(B是类,而不是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']

来自documentation

  

属性访问的默认行为是获取,设置或删除   来自对象字典的属性。例如,a.x有一个   查找链以。 dict [' x']开头,然后   键入(a)。 dict [' x'],并继续通过基类   (a)不包括元类。

这有点让人感到困惑" ...不包括元类..." ,这实际上意味着类型(a)的元类,因此说如果你的元类UpperMeta有一个元类TopMetaTopMeta定义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')

唯一能够正确解释元类的讨论:David Beazley - Python 3 Metaprogramming。你只有前80分钟左右。

答案 1 :(得分:1)

  

为什么B类有echo方法,B不是UpperMeta的子类,它   不应该有回音?

如果您查看What is a metaclass in Python?Customizing class creation,就会看到(来自python docs的引用)

  

如果定义了__metaclass__,则分配给它的可调用对象将是   调用而不是type()。

type()

  

本质上是类语句的动态形式。名称字符串   是类名,并成为__name__属性;基地   tuple逐项列出基类并成为__bases__属性;   dict字典是包含定义的命名空间   class body并成为__dict__属性。例如,   以下两个语句创建相同的类型对象:

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

这就是“就像”类扩展一样。这也回答了

  

什么属性类来自元类?

几乎所有东西。

还请be aware that

  

如果你想知道你是否需要它们,你就不会(那些人   实际上需要他们肯定地知道他们需要他们,而不是   需要解释为什么)。

然而在video posted by @Sebastian,他说

  问:你有太多的[元编程]   答:没有

所以他认为重要的是要学习。