Атрибут __name__
встроенных функций реализован (в ссылочном интерпретаторе CPython) как свойство (технически, дескриптор get-set), не хранится как атрибут в видеобъект Python.
Свойства действуют как атрибуты, но вызывают функцию при запросе значения, и в этом случае функция преобразует строковое имя функции в стиле C в Python str
по требованию .Поэтому каждый раз, когда вы смотрите вверх dir.__name__
, вы получаете заново построенный str
, представляющий данные; как отмечено в комментариях , это означает, что нет способа получить is
чек;даже dir.__name__ is dir.__name__
возвращает False
, потому что каждый поиск __name__
возвращал новый str
.
Язык не дает гарантий того, как реализован __name__
, поэтому вы не должны его предполагатьвозвращает один и тот же объект каждый раз.Существует очень мало гарантированных языком синглетонов (None
, True
, False
, Ellipsis
и NotImplemented
являются крупными, и все классы имеют уникальные идентичности);предполагать, что is
будет работать с чем-либо, не входящим в этот набор, если это не тот объект, который вы контролировали, создание которого является плохой идеей.Если вы хотите проверить, совпадают ли значения , протестируйте с помощью ==
, а не is
.
Обновление адреса для обхода произвольного графа объектов Python без получениязависает от дескрипторов и других вещей (например, __getattr__
), которые динамически генерируют объекты (и, следовательно, не должны вызываться для описания статического графа):
Функция inspect.getattr_static
должен позволять вам «обходить произвольный граф объектов Python, достижимый из начального, при минимальном предположении о типах объектов и реализации их атрибутов» (как ваш комментарий запрашивается ).Когда атрибут на самом деле является атрибутом, он возвращает значение, но не вызывает динамический поиск дескрипторов (например, @property
), __getattr__
или __getattribute__
.Так что inspect.getattr_static(dir, '__name__')
вернет getset_descriptor
, который CPython использует для реализации __name__
без фактического извлечения строки.В другом объекте, где __name__
является реальным атрибутом (например, сам модуль inspect
), он вернет атрибут (inspect.getattr_static(inspect, '__name__')
возвращает 'inspect'
).
Хотя он не идеален (некоторые свойствана самом деле может быть поддержано реальными объектами Python, а не динамически генерируемыми, к которым вы не можете получить доступ в противном случае), это по крайней мере работоспособное решение;вы не будете в конечном итоге создавать новые объекты случайно, и вы не попадете в бесконечные циклы поиска свойств (например, каждый вызываемый объект может __call__
проверять его вечно, оборачиваясь снова и снова)таким образом, вы можете, по крайней мере, прийти к решению, которое в основном точно отражает объектный граф и не в конечном итоге не вернется к смерти.
Примечательно, что оно будет правильно сохранять семантику идентичности.Если два объекта имеют одинаковый атрибут (по идентичности), результат будет соответствовать ожидаемому.Если два объекта совместно используют дескриптор (например, __name__
для всех встроенных функций, например, bin
, dir
), то он возвращает сам дескриптор, который будет соответствовать идентификатору.И все это делается без необходимости заранее знать, является ли то, что у вас есть, атрибутом или дескриптором.