Сканирование членов класса Python - Почему __bases__ рекурсивное сканирование требуется для получения членов?
Я нашел следующую функцию, но я понятия не имею, почему дополнительные __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 ответ
Действительно, dir()
Функция для классов уже включает в себя все классы, перечисленные в __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__()
методы.