Какова цель слова «я» в Python? - PullRequest
1013 голосов
/ 26 апреля 2010

Какова цель слова self в Python? Я понимаю, что это относится к конкретному объекту, созданному из этого класса, но я не понимаю, почему его нужно явно добавлять в каждую функцию в качестве параметра. Для иллюстрации, в Ruby я могу сделать это:

class myClass
    def myFunc(name)
        @name = name
    end
end

Что я понимаю, довольно легко. Однако в Python мне нужно включить self:

class myClass:
    def myFunc(self, name):
        self.name = name

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

Ответы [ 20 ]

652 голосов
/ 26 апреля 2010

Причина, по которой вам нужно использовать self., заключается в том, что Python не использует синтаксис @ для ссылки на атрибуты экземпляра. Python решил сделать методы так, чтобы экземпляр, к которому принадлежит метод, автоматически передавал , но не получил автоматически: первый параметр методов - это экземпляр, вызываемый методом на. Это делает методы полностью такими же, как функции, и оставляет фактическое имя для использования на ваше усмотрение (хотя self является соглашением, и люди обычно недовольны вами, когда вы используете что-то еще.) self не является особенным для код, это просто еще один объект.

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

399 голосов
/ 28 апреля 2010

Давайте возьмем простой векторный класс:

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

Мы хотим иметь метод, который вычисляет длину. Как бы это выглядело, если бы мы хотели определить его внутри класса?

    def length(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)

Как должно выглядеть, когда мы определяем его как глобальный метод / функцию?

def length_global(vector):
    return math.sqrt(vector.x ** 2 + vector.y ** 2)

Таким образом, вся структура остается прежней. Как я могу использовать это? Если мы на мгновение предположим, что мы не написали length метод для нашего Vector класса, мы могли бы сделать это:

Vector.length_new = length_global
v = Vector(3, 4)
print(v.length_new()) # 5.0

Это работает, потому что первый параметр length_global можно повторно использовать в качестве параметра self в length_new. Это было бы невозможно без явного self.


Еще один способ понять необходимость явного self - посмотреть, где Python добавляет немного синтаксического сахара. Если иметь в виду, что в основном это звонок типа

v_instance.length()

внутренне преобразуется в

Vector.length(v_instance)

Легко увидеть, куда входит self. На самом деле вы не пишете методы экземпляра в Python; то, что вы пишете, это методы класса, которые должны принимать экземпляр в качестве первого параметра. И, следовательно, вам придется явно указать параметр экземпляра где-нибудь.

346 голосов
/ 26 января 2014

Допустим, у вас есть класс ClassA, который содержит метод methodA, определенный как:

def methodA(self, arg1, arg2):
    # do something

и ObjectA является экземпляром этого класса.

Теперь, когда вызывается ObjectA.methodA(arg1, arg2), Python внутренне преобразует его для вас как:

ClassA.methodA(ObjectA, arg1, arg2)

Переменная self относится к самому объекту.

193 голосов
/ 28 июня 2015

Когда объекты создаются, сам объект передается в параметр self.

enter image description here

Из-за этого данные объекта привязываются к объекту. Ниже приведен пример того, как вы можете визуализировать, как могут выглядеть данные каждого объекта. Обратите внимание, как «self» заменяется именем объекта. Я не говорю, что приведенная ниже примерная диаграмма является полностью точной, но, надеюсь, она послужит цели визуализации использования себя.

enter image description here

Объект передается в параметр self, чтобы объект мог хранить свои собственные данные.

Хотя это может быть не совсем точно, подумайте о процессе создания экземпляра объекта, подобном этому: когда объект создается, он использует класс в качестве шаблона для своих собственных данных и методов. Без передачи своего собственного имени в параметр self атрибуты и методы в классе останутся как общий шаблон и не будут ссылаться на объект (принадлежать ему). Поэтому, передавая имя объекта в параметр self, это означает, что, если 100 объектов созданы из одного класса, все они могут отслеживать свои собственные данные и методы.

См. Иллюстрацию ниже:

enter image description here

71 голосов
/ 26 апреля 2010

Мне нравится этот пример:

class A: 
    foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: [5]

class A: 
    def __init__(self): 
        self.foo = []
a, b = A(), A()
a.foo.append(5)
b.foo
ans: []
34 голосов
/ 22 июня 2011

Я покажу с кодом, что не использует классы :

def state_init(state):
    state['field'] = 'init'

def state_add(state, x):
    state['field'] += x

def state_mult(state, x):
    state['field'] *= x

def state_getField(state):
    return state['field']

myself = {}
state_init(myself)
state_add(myself, 'added')
state_mult(myself, 2)

print( state_getField(myself) )
#--> 'initaddedinitadded'

Классы - это просто способ избежать постоянной передачи этого "состояния" (и других полезных вещей, таких как инициализация, составление классов, редко используемые метаклассы и поддержка пользовательских методов для переопределения операторов).

Теперь давайте продемонстрируем приведенный выше код с использованием встроенного механизма классов Python, чтобы показать, как это в основном то же самое.

class State(object):
    def __init__(self):
        self.field = 'init'
    def add(self, x):
        self.field += x
    def mult(self, x):
        self.field *= x

s = State()
s.add('added')    # self is implicitly passed in
s.mult(2)         # self is implicitly passed in
print( s.field )

[перенес мой ответ из дублированного закрытого вопроса]

17 голосов
/ 26 апреля 2010

Как и все другие причины, о которых уже говорилось, он упрощает доступ к переопределенным методам; Вы можете позвонить Class.some_method(inst).

Пример того, где это полезно:

class C1(object):
    def __init__(self):
         print "C1 init"

class C2(C1):
    def __init__(self): #overrides C1.__init__
        print "C2 init"
        C1.__init__(self) #but we still want C1 to init the class too
>>> C2()
"C2 init"
"C1 init"
17 голосов
/ 26 апреля 2010

Следующие отрывки взяты из документации Python о себе :

Как и в Modula-3, не существует сокращений [в Python] для ссылки на члены объекта из его методов: функция метода объявляется с явным первым аргументом, представляющим объект, который неявно предоставляется вызовом. *

Часто первый аргумент метода называется self. Это не более чем соглашение: имя self не имеет абсолютно никакого особого значения для Python. Тем не менее, обратите внимание, что из-за несоблюдения соглашения ваш код может быть менее читаемым для других программистов Python, и также возможно, что может быть написана программа для просмотра классов, основанная на таком соглашении.

Для получения дополнительной информации см. Учебник по документации Python для классов .

13 голосов
/ 30 августа 2012

Его использование аналогично использованию ключевого слова this в Java, т. Е. Для ссылки на текущий объект.

11 голосов
/ 25 мая 2015

Python не является языком, созданным для объектно-ориентированного программирования, в отличие от Java или C ++.

При вызове статического метода в Python просто пишется метод с обычными аргументами внутри него.

class Animal():
    def staticMethod():
        print "This is a static method"

Однако, объектный метод, который требует, чтобы вы создали переменную, которая является Animal, в этом случае требует аргумента self

class Animal():
    def objectMethod(self):
        print "This is an object method which needs an instance of a class"

Метод self также используется для ссылки на переменное поле в классе.

class Animal():
    #animalName made in constructor
    def Animal(self):
        self.animalName = "";


    def getAnimalName(self):
        return self.animalName

В этом случае self ссылается на переменную animalName всего класса. ПОМНИТЕ: Если у вас есть переменная в методе, self не будет работать. Эта переменная просто существует только во время работы этого метода. Для определения полей (переменных всего класса) вы должны определить их вне методов класса.

Если вы не понимаете ни слова из того, что я говорю, то Google "Объектно-ориентированное программирование". Как только вы это поймете, вам даже не нужно будет задавать этот вопрос:).

...