Почему __bases__ недоступен в теле класса? - PullRequest
6 голосов
/ 27 мая 2019

Объекты класса имеют атрибут __bases____base__):

>>> class Foo(object):
...     pass
... 
>>> Foo.__bases__
(<class 'object'>,)

К сожалению, эти атрибуты недоступны в теле класса, что было бы очень удобно для доступа к атрибутам родительского класса без необходимости жесткого кодирования имени:

class Foo:
    cls_attr = 3

class Bar(Foo):
    cls_attr = __base__.cls_attr + 2
    # throws NameError: name '__base__' is not defined

Есть ли причина, по которой __bases__ и __base__ не могут быть доступны в теле класса?

(Для ясности, я спрашиваю, является ли это сознательным проектным решением. Я не спрашиваю о реализации; я знаю, что __bases__ является дескриптором в type и что этот дескриптор не может быть доступ до тех пор, пока объект класса не был создан. Я хочу знать, почему python не создает __bases__ как локальную переменную в теле класса.)

Ответы [ 3 ]

6 голосов
/ 27 мая 2019

Я хочу знать, почему python не создает __bases__ как локальную переменную в теле класса

Как вы знаете, class - это в основном ярлык для type.__new__() - когда среда выполнения достигает операторов class, он выполняет все операторы на верхнем уровне тела class, собирает все полученные привязки в выделенный dict пространства имен вызывает type() с конкретным метаклассом, именем класса, базовыми классами и dict пространства имен и связывает результирующий объект класса с именем класса во вложенной области видимости (обычно, но не обязательно, на верхнем уровне модуля). Пространство имен).

Важным моментом здесь является то, что метакласс отвечает за создание объекта класса, и для обеспечения возможности создания объекта класса метакласс должен быть свободным делать с аргументами все, что он хочет. Чаще всего пользовательский метакласс будет работать в основном с диктовкой attrs, но он также должен иметь возможность связываться с аргументом bases. Теперь, когда метакласс вызывается только ПОСЛЕ того, как были выполнены операторы тела класса, среда выполнения не может надежно представить bases в области видимости тела класса, так как эти базы могут быть впоследствии изменены метаклассом.

Здесь также есть несколько более философских соображений, в частности, в отношении явного / явного по сравнению с неявным, и, как упоминает shx2, разработчики Python стараются избегать магических переменных, появляющихся на ровном месте. Действительно, есть пара переменных реализации (__module__ и, в py3, __qualname__), которые "автоматически" определены в пространстве имен тела класса, но это просто имена, в основном предназначенные в качестве дополнительной информации отладки / проверки для разработчиков) и не имеют абсолютно никакого влияния ни на создание объекта класса, ни на его свойства, поведение и тому подобное.

Как всегда в Python, вы должны учитывать весь контекст (модель исполнения, объектную модель, как разные части работают вместе и т. Д.), Чтобы действительно понять выбор дизайна. Согласны ли вы со всем дизайном и философией, это еще один спор (и тот, который здесь не относится), но вы можете быть уверены, что да, эти варианты являются «осознанными проектными решениями».

2 голосов
/ 27 мая 2019

Я не отвечаю на вопрос, почему это было решено реализовать так, как было, я отвечаю, почему он не был реализован как «локальная переменная в теле класса»:

Просто потому, чтоничто в python не является локальной переменной, магически определенной в теле класса.Python не любит имена, магически появляющиеся из ниоткуда.

0 голосов
/ 27 мая 2019

Это потому, что он просто еще не создан.

Обратите внимание на следующее:

>>> class baselessmeta(type):
...     def __new__(metaclass, class_name, bases, classdict):
...         return type.__new__(
...             metaclass,
...             class_name,
...             (), # I can just ignore all the base
...             {}
...         )
...
>>> class Baseless(int, metaclass=baselessmeta):
...     # imaginary print(__bases__, __base__)
...     ...
...
>>> Baseless.__bases__
(<class 'object'>,)
>>> Baseless.__base__
<class 'object'>
>>>

Что должно привести к воображаемому отпечатку? Каждый класс Python так или иначе создается с помощью метакласса type. У вас есть аргумент int для аргумента type() in bases, но вы не знаете, каким будет возвращаемое значение. Вы можете использовать это непосредственно в качестве базы в вашем метаклассе, или вы можете вернуть другую базу с вашим LOC.

Только что понял вашу to be clear часть, и теперь мой ответ бесполезен, ха-ха. О боже

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