关于python:为什么元类不能访问从元类定义的类的子类中固有的属性?

Why does a metaclass not have access to the attributes inhereited from a subclass of a class defined by the metaclass?

Foo是用元类Meta定义的。元类循环类属性,并将它们打印到屏幕上。

Bar类是Foo的子类。但是,元类不打印从bar继承的属性。

为什么元类不能访问Foo继承在Bar中的属性?我对Python的元类系统有什么不了解的?

这是2.7中的示例代码:

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


__init__attrs参数只包含该类的属性,而不包含其基。

Bar对象没有属性hi。相反,当您请求Bar.hi时,查找将从Bar开始,发现它没有hi,然后在基础Foo中查找它。


正如@orlp所说,attrs只包含正在创建的类的类字典。但是,您仍然可以访问hi,因为它在Foo的一个基的__dict__属性中。也就是说,您可以做一些类似于您所做的事情,但是可以通过基类进行循环,并打印出每个基类字典中的条目。

另一种方法是使用dir(),它应该大致返回一个类拥有的所有属性的列表。我大致说是因为一个类可以实现__getattr____getattribute__以"即时"返回属性,这意味着该类可能没有一组定义良好的属性供dir()返回--请参见此处的完整免责声明。但在许多常见的情况下,类似于以下内容的方法会起作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
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

哪些印刷品:

1
2
3
4
bases = (<type 'object'>,)
hi 1
bases = (<class '__main__.Foo'>,)
hi 1