Разговоры о «передаче по ссылке» только смущают вас. Сохраните эту терминологию для языков, где вы можете выбирать и где это имеет значение. В Python вы всегда передаете объекты вокруг - и эта передача эквивалентна «передаче по ссылке» - для всех объектов - от None до int в пул активных асинхронных сетевых подключений пример.
Учитывая это: алгоритм, которым следует язык для извлечения атрибутов из объекта, сложен, имеет детализацию - реализация __getattr__
является лишь верхушкой айсберга. Чтение документа под названием « Модель данных » в полном объеме даст вам лучшее представление о всех механизмах извлечения атрибутов.
Тем не менее, вот как это работает для методы "magi c" или "dunder" - (специальные функции с двумя подчеркиваниями перед и двумя после имени): когда вы используете оператор, который требует существования метода, который его реализует (например, __add__
для +
), язык проверяет класс вашего объекта на наличие метода __add__
, а не экземпляра. И __getattr__
в классе может динамически создавать атрибуты только для экземпляров этого класса. Но это не единственная проблема: вы можете создать метакласс (унаследованный от type
) и поместить метод __getattr__
в этот метакласс. Для всех запросов, которые вы делаете из Python, будет выглядеть так, как будто ваш объект имеет __add__
(или любой другой метод dunder) в своем классе. Однако для более сложных методов Python не go через обычный механизм поиска атрибутов - он «смотрит» непосредственно на класс, если «более сильный» метод существует «физически». В структуре памяти есть слоты, в которых хранятся классы для каждого из возможных методов обработки ошибок - и они либо ссылаются на соответствующий метод, либо имеют значение «null» (это «доступно для просмотра» при кодировании в C на Python сторона, по умолчанию dir
покажет эти методы, если они существуют, или опустите их, если нет). Если их там нет, Python просто «скажет», что объект не реализует эту операцию и точку.
Способ обойти это с таким прокси-объектом, как вы хотите, - создать прокси-класс, который либо содержит методы dunder из класса, который вы хотите обернуть, либо все возможные методы, и после вызова проверьте, реализует ли базовый объект вызываемый метод.
Именно поэтому «серьезный» код будет редко если вообще предложите истинные "прозрачные" прокси-объекты. Существуют исключения, но от «Weakrefs», до «super ()», до concurrent.futures, просто чтобы упомянуть некоторые из них в базовом языке и stdlib, никто не пытается «полностью работающий прозрачный прокси» - вместо этого api больше похоже на то, что вы вызываете метод ".value ()" или ".result ()" для оболочки, чтобы получить сам исходный объект.
Однако, можно сделать, как я описал выше. У меня даже есть небольшой (долго не поддерживаемый) пакет на pypi, который делает это, упаковывая прокси на будущее. Код: https://bitbucket.org/jsbueno/lelo/src/master/lelo/_lelo.py