Как динамически получить доступ к атрибутам объекта в Python без бокса? - PullRequest
0 голосов
/ 11 июля 2019

getattr(dir,"__name__") is dir.__name__ оценивается как False - есть ли альтернатива getattr, которая выдаст True?

1 Ответ

4 голосов
/ 11 июля 2019

Атрибут __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), то он возвращает сам дескриптор, который будет соответствовать идентификатору.И все это делается без необходимости заранее знать, является ли то, что у вас есть, атрибутом или дескриптором.

...