为啥元类不能访问由元类定义的类的子类继承的属性?
Posted
技术标签:
【中文标题】为啥元类不能访问由元类定义的类的子类继承的属性?【英文标题】:Why does a metaclass not have access to the attributes inhereited from a subclass of a class defined by the metaclass?为什么元类不能访问由元类定义的类的子类继承的属性? 【发布时间】:2015-07-06 16:40:59 【问题描述】:类 Foo
使用元类 Meta
定义。元类循环遍历类属性并将它们打印到屏幕上。
类Bar
子类Foo
。但是,元类不会打印从 Bar 继承的属性。
为什么元类不能访问Foo
在Bar
中继承的属性?我对 python 的元类系统有什么不了解的地方?
这是2.7
中的示例代码:
class Meta(type):
def __init__(cls, name, bases, attrs):
print "bases = ".format(bases)
items = k:v for k,v in attrs.iteritems() if not k.startswith('__')
for k,v in items.iteritems():
print k, v
class Foo(object):
__metaclass__ = Meta
hi = 1
# This prints:
# bases = (<type 'object'>,)
# hi 1
class Bar(Foo):
pass
# This prints:
# bases = (<class '__main__.Foo'>,)
Foo.hi
#prints 1
Bar.hi
#prints 1
【问题讨论】:
【参考方案1】:__init__
的 attrs
参数仅包含 该类 的属性,而不包含其基类的属性。
Bar
对象没有hi
属性。相反,当您请求Bar.hi
时,查找将从Bar
开始,发现它没有hi
,然后在基础Foo
中查找它。
【讨论】:
【参考方案2】:正如@orlp 所说,attrs
仅包含正在创建的类的类字典。但是,您仍然可以访问hi
,因为它位于Foo
的基础之一的__dict__
属性中。也就是说,您可以做一些与您所拥有的类似的事情,但通过基类递归并打印出每个基类字典中的条目。
另一种方法是使用dir()
,它应该大致返回一个类所有属性的列表。我说大致是因为一个类可以实现__getattr__
或__getattribute__
以“即时”返回属性,这意味着该类可能没有为dir()
定义明确的属性集返回 - 请参阅完整的免责声明 here。但在许多常见情况下,类似以下的方法会起作用:
class Meta(type):
def __init__(cls, name, bases, attrs):
print "bases = ".format(bases)
for attr in dir(cls):
if not attr.startswith('_'):
print attr, getattr(cls, attr)
class Foo(object):
__metaclass__ = Meta
hi = 1
class Bar(Foo):
pass
哪些打印:
bases = (<type 'object'>,)
hi 1
bases = (<class '__main__.Foo'>,)
hi 1
【讨论】:
以上是关于为啥元类不能访问由元类定义的类的子类继承的属性?的主要内容,如果未能解决你的问题,请参考以下文章