Который более фундаментален: функции Python или методы объекта Python?

Я пытаюсь получить концептуальное понимание природы функций Python и методов. Я добираюсь, который функционирует, на самом деле объекты, с методом, который называют, когда функция выполняется. Но то, что метод функционального объекта на самом деле другая функция?

Например:

def fred():
    pass

Если я смотрю на dir(fred), Я вижу, что этому назвали атрибут __call__. Но dir(fred.__call__) также назвали атрибут __call__. Делает fred.__call__.__call__ и так далее. Идентификаторы этой цепочки __call__ объекты предполагают, что они все отличны. Они, действительно возражает или этот некоторый прием низкого уровня интерпретатора?

Который более фундаментален: функции или методы объекта?

10
задан Stephan202 31 December 2009 в 14:59
поделиться

3 ответа

Что более фундаментально: функции или объектно-методы?

Думаю, лучшим ответом может быть "ни то, ни другое". Смотрите Execution model часть ссылки на Python, где она ссылается на "блоки". Вот что на самом деле выполняется. Вещь __call__, на которую вы зацикливались в бесконечном поиске конца - это просто обёртка, которая знает как выполнить блок кода (смотрите вместо этого различные атрибуты func_xxx вашей функции, где реальный байт-код хранится как func_code).

Также актуальна секция определений Function definitions, которая ссылается на "объект функции [являющийся] (оберткой вокруг исполняемого кода функции)". Наконец, есть термин вызываемый, который также может быть ответом на "что более фундаментально?"

.
1
ответ дан 4 December 2019 в 02:50
поделиться

Не совсем Python ответ, но на самом низком уровне процессор понимает только действия и переменные. Из этого мы экстраполируем функции, а из переменных и функций экстраполируем объекты. Поэтому с точки зрения низкоуровневого программирования я бы сказал, что более фундаментальным является функция.

Это не обязательно верно для Python в смысле Pythonic, и, наверное, является хорошим примером того, почему не всегда полезно глубоко вглядываться в реализацию языка как пользователя. :). Думать о функции как об объекте, безусловно, лучший ответ в самом языке Python.

Сначала я думал, что ваши вызовы отслеживаются в библиотеке Python, но метод .call обладает теми же самыми свойствами, что и любой другой метод. Таким образом, он рекурсивно исследует себя, я думаю, поиграв с python CLI несколько минут; я думаю, что это болезненный способ изучения архитектуры и, хотя это и не обязательно ошибка, свойство того, как Python обрабатывает объекты под обложками. :)

.
2
ответ дан 4 December 2019 в 02:50
поделиться

Короткий ответ: оба фундаментальны, .__call__() на функции - это просто виртуальный трюк.


Остальной ответ немного сложноват. Вам не обязательно понимать его, но я нахожу тему интересной. Предупреждаю, что представлю серию лжи, постепенно их исправляя.

Длинный ответ

На самом фундаментальном уровне можно сказать, что на Python есть всего 2 операции:

  • доступ к атрибуту: obj.attr
  • function call: callable(args)

вызовы методов - obj.method(args) - не являются фундаментальными. Они состоят из 2-х этапов: получение атрибута obj.method (который дает вызываемый "связанный метод" объекта) и называя это с помощью args.

Другие операторы определяются в терминах этих операторов. Например, x + y пытается x.__add__(y), возвращаясь к другим подобным комбинациям, если это не работает.

Бесконечно длинный ответ?

Пока что хорошо. Но сами вызовы и доступ к атрибутам также определены в терминах obj.__call__(args) и obj.__getattribute__(name)?!?
. Неужели это черепахи?!?

Хитрость в том, что операции над объектом определяются вызовом методов его типа : тип(obj).__call__(obj, args) и тип(obj).__getattribute__(obj, name). Что BTW означает, что я солгал вам, и есть третья фундаментальная операция:

  • получение типа объекта: type(obj)

OK, это все равно не помогает. type(obj).__call__(...) все еще включает в себя доступ к атрибуту и вызов, так что это должно продолжаться ad infinitum? Руб заключается в том, что в конечном итоге Вы попадаете в тип builtin - обычно это функция, объект или тип - и для них доступ к атрибутам и вызов функций являются фундаментальными.

Таким образом, при вызове экземпляра пользовательского класса, это действительно реализуется с помощью его метода __call__. Однако его метод __call__, скорее всего, является обычной функцией, которую можно вызывать напрямую. Конец тайны.

Аналогично с __getattribute__ - вы можете предоставить ему доступ к атрибуту define для вашего класса, но сам класс принципиально реализует доступ к атрибуту (если только он не имеет пользовательского metaclass).

The Curtain in Front of the Man

Так почему же даже функция имеет метод fred.__call__? Ну, это просто дым и зеркала, которые Python вытягивает, чтобы размыть разницу между встроенными типами и пользовательскими классами. Этот метод существует на всех вызываемых объектах, но вызов нормальной функции не обязательно должен через него проходить - функции в принципе вызываемые.

Аналогично, все объекты имеют obj.__getattribute__ и obj. __class__, но для встроенных типов только раскрывает фундаментальные операции вместо , определяя его.

Мелким шрифтом

Первое утверждение, что на Python было 2 фундаментальных операции, на самом деле было полной ложью. Технически, все операторы на питоновском языке имеют "фундаментальную" операцию на уровне Си, выставленную для согласованности через метод, а пользовательские классы могут переопределить эти операции с помощью подобных методов.

Но история, которую я рассказал, могла быть правдой, и это уменьшает вопрос о её центре: почему .__call__() и .__getattribute__() не является бесконечной рекурссией.

.
4
ответ дан 4 December 2019 в 02:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: