Классы нового стиля Python и функция __subclasses__ - PullRequest
15 голосов
/ 20 мая 2010

Может кто-нибудь объяснить мне, почему это работает (в 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__», но я не уверен, почему. Я знаю, что это связано с классами старого и нового стиля, но я не понимаю, почему это сделает эту функциональность недоступной.

Пояснение: Я хочу понять, ПОЧЕМУ __subclasses__() недоступен в старом стиле, я понимаю, что метод не существует для классов старого стиля, но я не получаю что нового в стиле, который делает возможными эти новые функции.

Ответы [ 2 ]

30 голосов
/ 21 мая 2010
class Foo(object):
    pass

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

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

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

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

class Foo():
    pass

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

Обратите внимание, если вы не понимаете, почему у класса старого стиля нет метода __ подклассов __ , вы всегда можете запустить интерпретатор 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__']
3 голосов
/ 29 июля 2013

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

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, наследуя базовый класс «object» в каждом определении класса.

Так что, если вы делаете в 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, вам нужно наследовать объект класс в вашем определении класса.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...