Сравнение PHP __get () с __get __ () и __getattr __ () в Python

В чем разница между __get__() и __getattr__() в Python? Я исхожу из фона PHP, где есть только __get() . Когда следует использовать эту функцию?

Я пытался понять это на некоторое время. Я вижу много таких вопросов, как этот , спрашивая о различии между __getattr__() и __getattribute__() .

Solutions Collecting From Web of "Сравнение PHP __get () с __get __ () и __getattr __ () в Python"

Здесь вы найдете подробную документацию по всем этим методам.

Исходя из PHP, вы должны сначала познакомиться с объектной моделью Python. Это намного богаче, чем PHP, поэтому вы не должны пытаться сопоставить свои знания PHP 1: 1 с Python. Если вы хотите разработать PHP, используйте PHP. Если вы хотите развиваться в Python, изучите Python.

Возвращаясь к исходному вопросу: __getattr__ , вероятно, является функцией, которая выполняет те же функции, что и функция __get в PHP. __get__ в Python используется для реализации дескрипторов. Подробности о дескрипторах также можно найти в документации, упомянутой выше.

Прежде всего, PHP не имеет эквивалента __get__() Python __get__() даже не закрывается! То, что вы ищете, определенно __getattr__() .

Я __get__ из фона PHP, где есть только __get__

PHP имеет магический метод __get() , который вызывается всякий раз, когда вы пытаетесь получить доступ к свойству, которого не существует.

Краткий список неэквивалентов

Во-первых, давайте проясним некоторые вещи:

  • PHP не имеет эквивалента __get__() Python
  • PHP не имеет эквивалента __getattr__() Python __getattr__()
  • PHP не имеет эквивалента __getattribute__()
  • У Python нет эквивалента PHP __get()

(И для всех методов сеттера соответственно.)

Вопреки предположению Ахима, __get() не делает то же самое, что и __getattr__() Python!
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 – это небольшой шаг вперед, хотя)
  • но obj Python этого не делает.

Это позволяет 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 .