Классы нового стиля Python и функция __subclasses__

Может кто-нибудь объяснить мне, почему это работает (в Python 2.5):

class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

но это не так:

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

Последний возвращает "AttributeError: класс Foo не имеет атрибута" __subclasses__ ", но я не уверен, почему. Я знаю, что это связано со старыми классами против классов нового стиля, но я не понимаю, почему это сделает эту функцию недоступной.

Уточнение: Я ищу, чтобы понять WHY __subclasses__() недоступен в старом стиле, я понимаю, что метод не существует для классов старого стиля, но я не получить то, что касается нового стиля, что делает эти новые функции возможными.

Ответ 1

class Foo(object):
    pass

Класс выше - это класс "нового стиля", потому что он наследует класс object. Классы нового стиля предоставляют множество дополнительных фреймворков, которые не имеют классов "старого стиля". Одним из атрибутов класса нового стиля является возможность определять подклассы класса с помощью метода __ подклассов __.

Есть некоторые good обсуждение о классах нового стиля и методе __ подклассы __, которые используются полностью недокументированные. (Здесь является неофициальным объяснением Тима Петерса.)

"Каждый класс нового стиля хранит список слабых ссылок на его непосредственные подклассы. Этот метод возвращает список всех этих ссылок, которые все еще живы".

Итак, чтобы ответить на ваш вопрос, функциональность ___ подклассов __ недоступна, потому что в вашем втором примере:

class Foo():
    pass

Класс старого стиля Foo не наследуется от объекта (так что это не класс нового стиля), и там для него не наследуется метод __ подклассов __.. p >

Обратите внимание: если вы не понимаете, почему класс старого стиля не имеет метода ___ подклассов __, вы всегда можете запустить интерпретатор python и провести некоторую проверку с помощью dir

>>> class Foo(object):
...     pass
...
>>> dir(Foo.__class__)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__doc__', '__
eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__instancecheck__', '__itemsize__', '__le__', '__lt
__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__s
ubclasscheck__', '__subclasses__', '__subclasshook__', '__weakrefoffset__', 'mro']
>>> class Bar():
...     pass
...
>>> dir(Bar.__class__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class Bar has no attribute '__class__'
>>> dir(Bar)
['__doc__', '__module__']
>>> dir(Foo)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '
__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

Ответ 2

Добавление к ответу выше.

Python 3.0 имеет отдельную реализацию классов. Подкласс - это функция в Python 3.0, а не Python 2.0.

Итак, если вы устанавливаете python 3.x и делаете

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

Он не даст никакой ошибки атрибута.

Теперь такая же функциональность распространяется на классы Python 2.0, наследуя базовый класс "объект" в каждом определении класса.

Итак, если вы делаете в Python 2.x:

class Foo(object):
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

Поскольку вы наследуете базовый класс object в новом классе Foo, класс стиля 3.x наследуется и не возникает ошибка атрибута.

Но когда вы делаете в Python 2.x

class Foo():
    pass

class Bar(Foo):
    pass

print(Foo.__subclasses__())

это означает, что новые классы стиля не были унаследованы, и поскольку подкласс является частью новых классов стилей, он выдает ошибку атрибута.

Поэтому помните, что если вы хотите расширить функциональность класса Python 3.x до Python 2.x, вам необходимо наследовать класс object в определении класса.

Надеюсь, это поможет.