Зачем вам явно нужен аргумент "self" в методе Python? - PullRequest
182 голосов
/ 16 сентября 2008

При определении метода для класса в Python он выглядит примерно так:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

Но в некоторых других языках, таких как C #, у вас есть ссылка на объект, к которому привязан метод, с ключевым словом "this" без объявления его в качестве аргумента в прототипе метода.

Было ли это намеренным решением о разработке языка в Python или есть некоторые подробности реализации, которые требуют передачи "self" в качестве аргумента?

Ответы [ 9 ]

88 голосов
/ 16 сентября 2008

Мне нравится цитировать «Питерский дзен питона». «Явное лучше, чем неявное».

В Java и C ++ 'this.' может быть выведено, кроме случаев, когда у вас есть имена переменных, которые делают невозможным вывод. Так что иногда вам это нужно, а иногда нет.

Python решает сделать такие вещи явными, а не основанными на правиле.

Кроме того, поскольку ничего не подразумевается и не предполагается, части реализации предоставляются. self.__class__, self.__dict__ и другие «внутренние» структуры доступны очевидным образом.

57 голосов
/ 16 сентября 2008

Это чтобы минимизировать разницу между методами и функциями. Он позволяет легко создавать методы в метаклассах или добавлять методы во время выполнения к уже существующим классам.

, например

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

Это также (насколько мне известно) облегчает реализацию среды выполнения Python.

51 голосов
/ 21 ноября 2008

Я предлагаю прочитать блог Гвидо ван Россума на эту тему - Почему явное Я должно остаться .

Когда определение метода оформлено, мы не знаем, нужно ли автоматически дать ему параметр «self» или нет: декоратор может превратить функцию в статический метод (у которого нет «self») или класс метод (который имеет забавный вид self, который ссылается на класс вместо экземпляра), или он может сделать что-то совершенно другое (тривиально написать декоратор, который реализует '@classmethod' или '@staticmethod' в чистом Python) Нет никакого способа не знать, что делает декоратор, наделять ли определяемый метод неявным аргументом «я» или нет.

Я отвергаю хаки, такие как '@classmethod' и'@staticmethod '.

16 голосов
/ 16 сентября 2008

Python не заставляет вас использовать "себя". Вы можете дать ему любое имя, какое захотите. Вам просто нужно помнить, что первый аргумент в заголовке определения метода является ссылкой на объект.

6 голосов
/ 12 июля 2015

Также позволяет вам сделать это: (короче говоря, вызов Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5) вернет 12, но сделает это самым безумным способом.

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

Конечно, это сложнее представить в таких языках, как Java и C #. Сделав ссылку на себя явной, вы можете ссылаться на любой объект по этой ссылке. Кроме того, такой способ игры с классами во время выполнения сложнее сделать на более статичных языках - не обязательно это хорошо или плохо. Просто явное я допускает существование всего этого безумия.

Кроме того, представьте себе следующее: мы хотели бы настроить поведение методов (для профилирования или для какой-то безумной черной магии). Это может привести нас к мысли: что если бы у нас был класс Method, поведение которого мы могли бы переопределить или контролировать?

Ну вот оно:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

А теперь: InnocentClass().magic_method() будет действовать как ожидалось. Метод будет привязан с параметром innocent_self к InnocentClass, а с magic_self - к экземпляру MagicMethod. Странно, да? Это как 2 ключевых слова this1 и this2 в таких языках, как Java и C #. Подобная магия позволяет фреймворкам делать вещи, которые в противном случае были бы гораздо более многословными.

Опять же, я не хочу комментировать этику этого материала. Я просто хотел показать вещи, которые было бы труднее сделать без явной ссылки на себя.

2 голосов
/ 01 мая 2016

Я думаю, что настоящая причина, помимо "Дзен Python", заключается в том, что функции - это граждане первого класса в Python.

Что по существу делает их Объектом. Теперь фундаментальный вопрос: если ваши функции также являются объектами, то в объектно-ориентированной парадигме как бы вы отправляли сообщения объектам, если сами сообщения являются объектами?

Похоже на проблему с куриным яйцом. Чтобы уменьшить этот парадокс, единственный возможный способ - передать контекст выполнения методам или обнаружить его. Но так как python может иметь вложенные функции, это невозможно сделать, так как контекст выполнения изменится для внутренних функций.

Это означает, что единственно возможное решение - явно передать «я» (контекст выполнения).

Так что я считаю, что это проблема реализации, дзен появился намного позже.

2 голосов
/ 31 марта 2015

Я думаю, что это связано с ПКП 227:

Имена в области видимости недоступны. Имена разрешены в самая внутренняя область действия функции. Если определение класса происходит в цепочка вложенных областей, процесс разрешения пропускает класс определения. Это правило предотвращает нечетные взаимодействия между классом атрибуты и доступ к локальной переменной. Если операция связывания имени происходит в определении класса, он создает атрибут в результате Объект класса. Чтобы получить доступ к этой переменной в методе или в функции вложенный в метод, ссылка на атрибут должна использоваться, либо через себя или через имя класса.

0 голосов
/ 04 февраля 2019

Как объяснено в Я в Python, Демистифицировано

что-нибудь вроде obj.meth (args) становится Class.meth (obj, args). Вызывающий процесс является автоматическим, в то время как процесс получения не является (его явным). По этой причине первым параметром функции в классе должен быть сам объект.

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from origin"""
        return (self.x**2 + self.y**2) ** 0.5

Вызовы:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () определяет три параметра, но мы только что передали два (6 и 8). Точно так же для distance () требуется один, но передано ноль аргументов.

Почему Python не жалуется на это несоответствие номера аргумента ?

Обычно, когда мы вызываем метод с некоторыми аргументами, вызывается соответствующая функция класса, помещая объект метода перед первым аргументом. Таким образом, что-нибудь вроде obj.meth (args) становится Class.meth (obj, args). Процесс вызова является автоматическим, в то время как процесс получения не является (его явным).

По этой причине первым параметром функции в классе должен быть сам объект. Запись этого параметра как self - это просто соглашение . Это не ключевое слово и не имеет особого значения в Python. Мы могли бы использовать другие имена (как это), но я настоятельно рекомендую вам не делать этого. Использование имен, отличных от self, осуждается большинством разработчиков и ухудшает читабельность кода («Количество читабельности»).
...
В первом примере self.x является атрибутом экземпляра, тогда как x является локальной переменной. Они не одинаковы и лежат в разных пространствах имен.

Я здесь, чтобы остаться

Многие предлагали сделать self ключевым словом в Python, например, в C ++ и Java. Это исключило бы избыточное использование явного self из списка формальных параметров в методах. Хотя эта идея кажется многообещающей, этого не произойдет. По крайней мере, не в ближайшее время. Основная причина - обратная совместимость . Вот блог от самого создателя Python, объясняющий, почему явное «я» должно оставаться.

0 голосов
/ 16 сентября 2008

Существует также еще один очень простой ответ: согласно дзен python , «явное лучше, чем неявное».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...