Сканирование членов класса Python-почему рекурсивное сканирование баз требуется в get-членах?
Я нашел следующую функцию, но я понятия не имею, почему требуется дополнительное __bases__
сканирование:
def getMembersWithBases(classType):
members = set(dir(classType))
# recursive bases scan
for baseClassType in classType.__bases__:
members.update(getMembersWithBases(baseClassType))
return members
Следующая функция быстрее и дает те же результаты - так почему же требуется дополнительное __bases__
сканирование в al?
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__
(через метакласс, classmethod недостаточно):Если объект имеет метод с именем
__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__()
.