Python类成员扫描 - 为什么在get成员中需要__bases__递归扫描?

时间:2012-10-31 08:51:34

标签: python introspection base-class

我找到了以下功能,但我不知道为什么需要进行额外的__bases__扫描:

def getMembersWithBases(classType):
    members = set(dir(classType))
    # recursive bases scan
    for baseClassType in classType.__bases__:
        members.update(getMembersWithBases(baseClassType))
    return members

以下功能更快并且结果相同 - 那么为什么需要进行额外的__bases__扫描呢?

def getMembers(classType):
    members = set(dir(classType))
    return members

一些包含新旧类的测试代码:

class Father(object):
    def testFather():
        pass

class Mother(object):
    def testMother():
        pass

class Child(Father, Mother):
    def testChild():
        pass

print type(Child)
print getMembers(Child) == getMembersWithBases(Child)                                             

class Father:
    def testFather():
        pass

class Mother:
    def testMother():
        pass

class Child(Father, Mother):
    def testChild():
        pass

print type(Child)
print getMembers(Child) == getMembersWithBases(Child)

结果:

<type 'type'>
True
<type 'classobj'>
True

1 个答案:

答案 0 :(得分:4)

确实,对于类,dir() function已经包含__bases__中列出的所有类:

  

如果对象是类型或类对象,则列表包含其属性的名称,并且递归地包含其基础的属性。

但是,通过指定__dir__方法(通过元类,类方法是不够的),类可以覆盖该行为:

  

如果对象具有名为__dir__()的方法,则将调用此方法,并且必须返回属性列表。

当存在__dir__()方法时,__bases__不会被递归:

>>> class Foo(object):
...     def spam(self): pass
... 
>>> class Bar(object):
...     def ham(self): pass
... 
>>> class CustomDirMetaclass(type):
...     def __dir__(cls):
...         return ['eggs']
... 
>>> class Baz(Foo, Bar):
...     __metaclass__ = CustomDirMetaclass
...     def eggs(self): pass
... 
>>> dir(Baz)
['eggs']
>>> getMembers(Baz)
set(['eggs'])
>>> getMembersWithBases(Baz)
set(['__module__', '__getattribute__', 'eggs', '__reduce__', '__subclasshook__', '__dict__', '__sizeof__', '__weakref__', '__init__', 'ham', '__setattr__', '__reduce_ex__', '__new__', 'spam', '__format__', '__class__', '__doc__', '__delattr__', '__repr__', '__hash__', '__str__'])

因此,__bases__类方法中getMembersWithBases()的显式递归可能是绕过任何自定义__dir__()实现的尝试。

否则,__bases__上的递归完全是多余的。

在我个人看来,__bases__的递归甚至是,如果 __dir__()方法存在于类层次结构中。在这种情况下,__dir__()方法覆盖是错误的,因为 方法应该递归__bases__中列出的类以正确模仿dir()函数的行为

说实话,我怀疑你找到的函数的作者并不知道dir()的递归性质,并且针对__bases__递归添加,而不是作为绕过自定义的手段__dir__()方法。