Python 类成员扫描 - 为什么在获取成员时需要 __bases__ 递归扫描?

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

最佳答案

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

If the object is a type or class object, the list contains the names of its attributes, and recursively of the attributes of its bases.

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

If the object has a method named __dir__(), this method will be called and must return the list of attributes.

当存在 __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__'])

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

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

在我个人看来,即使if__dir__()方法,__bases__上的递归也是多余的存在于类层次结构中。在这种情况下,__dir__() 方法重写是错误的,因为 方法应该递归 __bases__ 中列出的类以正确模仿行为dir() 函数。

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

关于Python 类成员扫描 - 为什么在获取成员时需要 __bases__ 递归扫描?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13154226/

相关文章:

ruby - 在 Ruby 中,有没有办法找到响应方法调用的类?

c++ - 指向派生类的指针是否首先创建基类?

python - Django 代码在本地和服务器上的行为不同

python - 将日期(excel 格式)的数字表示形式转换为 python 日期和时间,然后将它们拆分为 pandas 中两个单独的数据框列

python - 如何从 Python 类中查找属性名称

c++ - 遍历 POD 成员

java - 基类的运行时确定

c++ - 将默认复制构造函数替换为基类的复制构造函数 (c++)

python - 在 Python 中产生 2 次方的按位运算

python - 安装核心 ML 工具时出错