Ответ 1
Здесь вы найдете подробную документацию для всех этих методов здесь.
Исходя из PHP, вы должны сначала познакомиться с объектной моделью Python. Это намного богаче, чем PHP, поэтому вы не должны пытаться сопоставить свои знания PHP 1:1 с Python. Если вы хотите разработать PHP, используйте PHP. Если вы хотите развиваться в Python, изучите Python.
Возвращаясь к исходному вопросу: __getattr__
, вероятно, является функцией, которая выполняет ту же функцию, что и функция __get
в PHP. __get__
в Python используется для реализации дескрипторов. Подробности о дескрипторах также можно найти в документации, упомянутой выше.
Ответ 2
Прежде всего, PHP имеет не эквивалент Python __get__()
– даже не близко! То, что вы ищете, определенно __getattr__()
.
Я исхожу из фона PHP, где есть только __get__
PHP имеет магический метод, называемый __get()
, который вызывается всякий раз, когда вы пытаетесь открыть свойство, которое не существует.
Краткий список неэквивалентов
Во-первых, оставьте некоторые вещи:
- PHP не имеет эквивалент Python
__get__()
- PHP имеет не эквивалент Python
__getattr__()
- PHP не имеет эквивалент Python
__getattribute__()
- Python не имеет эквивалент PHP
__get()
(И для всех методов setter соответственно.)
Вопреки предположению Ахима, __get()
делает не делать то же, что и Python __getattr__()
!
Python не различает методы и свойства, но PHP делает, поэтому PHP имеет второй метод: __call()
.
__call()
выполняется всякий раз, когда вы пытаетесь вызвать метод для объекта, который не существует. Python не имеет эквивалента для этого, потому что метод - это просто объект (атрибут), который можно вызвать.
Пример в PHP:
<?php
$obj = new stdClass();
($obj->test)();
В Python это закончилось бы с помощью AttributeError
. Однако в PHP это даже не компилируется:
Ошибка анализа: синтаксическая ошибка, неожиданная '(' on line 4
Сравните это с Python:
obj.method()
# is eqvuivalent to:
(obj.method)()
Это важное различие. Мы заключаем, что способ PHP и Python думать о вызовах методов совершенно разные.
PHP "осведомленность о вызовах"
- PHP
obj
знает, который вы вызываете методом
- вы можете явно обрабатывать вызовы несуществующих методов на объект, который вы вызываете
- это потому, что модель выражения PHP очень несовместима (PHP 5.4 - это небольшой шаг вперед, хотя)
- но Python
obj
делает не.
Это позволяет PHP иметь obj.does_not_exist
для оценки до 3
, но obj.does_not_exist()
до 5
.
Насколько мне известно, на Python это невозможно сделать. (Это позволило бы нам описать непоследовательность PHP как функцию.)
Таким образом, мы можем расширить наш "неэквивалентный" список одним номером пули:
- Python не имеет эквивалент PHP
__call()
/__callStatic()
Подведение итогов
PHP предоставляет два отдельных механизма:
-
__get()
для несуществующих свойств
-
__call()
для вызовов несуществующих методов
Python имеет только один механизм, поскольку он не различает свойства и методы, поскольку он касается всех атрибутов.
-
__getattr__()
вызывается, когда атрибут не существует.
-
obj.non_existing()
не является специальным "синтаксисом вызова", это выражение, к которому применяется оператор вызова ()
: (obj.__getattr__("non_existing"))()
Отказ от ответственности: __getattr__()
не всегда вызывается, когда атрибут не существует. __getattribute__()
принимает наивысший приоритет в цепочке поиска и поэтому может игнорировать __getattr__()
.
дескрипторы
__get__()
в Python - это нечто совершенно отличное от того, что было рассмотрено выше.
Документация описывает дескрипторы как "a descriptor is an object attribute with "binding behavior""
. Я могу сформировать интуитивное понимание того, что подразумевается под "обязательным поведением", но только потому, что я уже понимаю, что делают дескрипторы.
Я бы решил описать дескрипторы как " самосознающие атрибуты", которые могут быть разделены между несколькими классами.
Позвольте мне объяснить, что я имею в виду под "самосознанием". Такие атрибуты:
- знать, когда они обращаются или читаются из
- знать, когда они записываются в
- знать, кого они читают/записывают через
- знать при удалении
Эти атрибуты являются независимыми объектами: объектами "дескриптор", т.е. объектами, которые придерживаются так называемого "протокола дескриптора" , который определяет набор методов вместе с их соответствующей сигнатурой, которую могут реализовать такие объекты.
Объект не имеет атрибута дескриптора. Фактически, они принадлежат к соответствующему классу (или его предку). Однако один и тот же объект дескриптора может "принадлежать" нескольким классам.
Примечание: "с кем они читаются", каков правильный способ ссылаться на obj
в obj.attr
? Я бы сказал: attr
доступен "через" obj
.