【问题标题】:why global variable __metaclass__ not working?为什么全局变量 __metaclass__ 不起作用?
【发布时间】:2019-09-27 03:43:01
【问题描述】:

我在这里定义了一些函数,它将所有用户定义的属性都变成大写

def up(name, parent, attr):
    user_defined_attr = ((k, v) for k, v in attr.items() if not k.startswith('_'))
    up_attr = {k.upper(): v for k,v in user_defined_attr}
    return type(name, parent, up_attr)

例如:

my_class = up('my_class', (object,), {'some_attr': 'some_value'})

hasattr(my_class, 'SOME_ATTR')
True

这是python doc中关于元类

的一些话

https://docs.python.org/2/reference/datamodel.html?highlight=metaclass#metaclass

The appropriate metaclass is determined by the following precedence rules:

If dict['__metaclass__'] exists, it is used.
Otherwise, if there is at least one base class, its metaclass is used (this looks for a __class__ attribute first and if not found, uses its type).
Otherwise, if a global variable named __metaclass__ exists, it is used.
Otherwise, the old-style, classic metaclass (types.ClassType) is used.

所以我做了一些测试

>>> def up(name, parent, attr):
...     user_defined_attr = ((k, v) for k, v in attr.items() if not k.startswith('_'))
...     up_attr = {k.upper(): v for k,v in user_defined_attr}
...     return type(name, parent, up_attr)
... 
>>> 
>>> 
>>> __metaclass__ = up
>>> 
>>> class C1(object):
...     attr1 = 1
... 
>>> hasattr(C1, 'ATTR1')
False

不适用于全局 var 案例,为什么?

【问题讨论】:

  • 那是 Python 2 文档。你 Python 2吗? Python 3 改变了一切。
  • 另外,你列出了一个基类,所以无论如何你都不会碰到全局变量。

标签: python python-2.7 metaclass


【解决方案1】:

似乎只有旧式类使用全局__metaclass__ 变量。它们是旧式的这一事实与此无关,但这是它们的定义方式。新式类显式继承自具有元类的类,而旧式类则没有。

class Meta(type):
    pass


__metaclass__ = Meta


class NewStyle(object):
    pass

class OldStyle:
    pass


print "new style", type(NewStyle)
print "old style", type(OldStyle)

此代码打印:

new style <type 'type'>
old style <class '__main__.Meta'>

这似乎与您列出的规则一致。 NewStyle 具有基类 object,并且该类具有自己的元类 type。所以对于新式类type是根据秒规则选择的。

【讨论】:

  • 这不是旧式或新式的问题。如果列出了任何基类,旧式类也不会使用全局 __metaclass__。此外,您的 OldStyle 课程确实是新式的,您可以通过检查 isinstance(OldStyle, type) 看到。
  • @user2357112 isinstance(OldStyle, type) 应为我返回False,还是我错过了什么?我同意行为上的差异不是由旧式/新式引起的,而是由它们的定义方式引起的。
  • @user2357112 另外,即使一个旧式类继承自另一个没有元类的旧式类,也会使用全局变量。
【解决方案2】:

如果您使用的是 Python 2,您的问题是您将 object 列为 C1 的基类,而全局 __metaclass__ 回退的优先级低于基类的元类。

如果您使用的是 Python 3,您的问题是全局 __metaclass__ 不再执行任何操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 2019-01-20
    • 2013-07-13
    • 2021-11-14
    • 1970-01-01
    • 2016-12-30
    相关资源
    最近更新 更多