Какова цель слова «я»?


1132

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

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

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

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

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


111
Вы можете найти интересным это эссе Гвидо ван Россума «Почему явное я должен остаться»: neopythonic.blogspot.com/2008/10/…
unutbu

14
См. Также «Почему« self »должно использоваться явно в определениях и вызовах методов
unutbu,

37
«Что я понимаю, довольно легко» --- Довольно субъективно, вы не думаете? Что делает @nameболее интуитивным, чем self.name? Последний, IMO, более интуитивно понятен.
Санта

14
В этом ключевое отличие функции от метода класса. Функция свободна, свободна от нуля. Метод класса (экземпляра) должен знать о его родителе (и родительских свойствах), поэтому вам нужно передать методу ссылку на родительский класс (как self ). Это всего лишь одно неявное правило, которое вы должны усвоить, прежде чем понимать ООП. Другие языки предпочитают синтаксический сахар семантической простоте, Python не является другими языками.
Эван Плейс

9
Я не думаю, что «явный лучше, чем неявный» действительно хорошо объясняет этот выбор дизайна. @fooи self.fooв равной степени явные, поскольку не требуется никакого неявного разрешения (например, в C ++ к членам экземпляра можно «неявно» обращаться без «явного» использования пространств имен). Единственное отличие состоит в том, что Ruby вводит новую семантику (@), а Python - нет. Стоит ли новая семантика того количества, которого избегают многословия, чисто субъективно. Тем не менее, следует отметить, что большинство современных языков предпочитают вводить понятие здесь (например, php's $ this, JS's this).
Цзин

Ответы:


710

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

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


23
@Georg: clsотносится к объекту класса, а не к объекту экземпляра
SilentGhost

17
@SilentGhost: На самом деле имя первого параметра такое, каким вы хотите его видеть. О методах класса, соглашение заключается в использовании clsи selfиспользуется обычно для методов экземпляра. Если бы я хотел, я мог бы использовать selfдля методов класса и, clsнапример, методы. Я мог бы также использовать bobи, fnordесли мне понравилось.
SingleNegationElimination

67
Мне интересно, что сообщество не выбрало thisвместо self. Есть ли selfкакая-то история, о которой я не знаю в старых языках программирования?
Жюль GM

24
@Julius selfПришли из конвенций Modula-3, см. Этот ответ для более подробной информации об этом выборе. (Отказ от ответственности: это мое).
Бакуриу

9
@Julius selfКлючевое слово (Smalltalk, 1980) предшествует thisключевому слову (из C ++). См .: stackoverflow.com/questions/1079983/…
Уэс Тёрнер

425

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

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; вы пишете методы класса, которые должны принимать экземпляр в качестве первого параметра. И, следовательно, вам придется явно указать параметр экземпляра где-нибудь.


4
Vector.length_new = length_global ... Я фактически начал использовать синтаксис, подобный этому, в моих объявлениях класса. Всякий раз, когда я хочу наследовать только некоторые методы из другого класса, я просто копирую ссылку на методы.
Jeeyoung Ким

2
Было бы справедливо сказать, что «метод экземпляра» в Python - это просто синтаксический сахар статических глобальных методов (как в Java или C ++) с объектом экземпляра, переданным для упаковки нескольких атрибутов? --- ну, это наполовину правда, так как в полиморфизме более важная цель "this" (как в java) или "self" - дать вам правильную реализацию методов. У Python есть это. поэтому вызов myobj.someMethod () в Python равен TheClassOfMyObj.someMethod (myobj). обратите внимание, что TheClassOfMyObj автоматически определяется python из "self", в противном случае вам придется это выяснить.
Тедди Тедди

3
На самом деле, методы Vector.length_new = length_globalпоказывают, что методы экземпляра - это не только методы класса, но и просто функции, которые являются членами класса .
RussW

1
«Это работает, потому что первый параметр length_global может быть повторно использован в качестве параметра self в length_new. Это было бы невозможно без явного self». - это будет работать точно так же. это было бы повторно использовано для неявного "я" ... второй пример - циклическое рассуждение - вы должны явно поместить себя туда, потому что python нуждается в явном "я".
Кароли Хорват

1
@KarolyHorvath: Конечно, также было бы возможно иметь язык с моделью, в которой внутренне определенные методы не нуждаются в явном самоопределении, а внешне определенные методы. Но я бы сказал, что есть определенная последовательность в требовании явного «я» в обоих случаях, что делает законным основание делать это таким образом. Другие языки могут выбирать разные подходы.
Дебильски

423

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

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

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

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

ClassA.methodA(ObjectA, arg1, arg2)

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


94
Я прочитал все остальные ответы и вроде как понял, я прочитал этот, и тогда все это имело смысл.
Сет

3
Это прибило это для меня!
Бернард 'Beta Berlin' Парах

2
Почему бы не держать эти внутренности внутри, как это делает Руби?
Сис Тиммерман

Но в методе __init __ (self) он принимает self, а затем, даже не создавая объект, как он ссылается на себя?
Саурав

Серьезно, это намного лучше, чем пример Дебилски, потому что он не слишком сложен, и люди могут быть не знакомы с векторами.
NoName

215

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

введите описание изображения здесь

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

введите описание изображения здесь

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

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

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

введите описание изображения здесь


Привет, когда вы обращаетесь к атрибутам Боба, например, с помощью "bob.name ()", вы на самом деле получаете доступ к bob (). Self.name, так сказать из права ' init '?
udarH3

3
Когда вы пишете bob.name () в приведенном выше комментарии, вы подразумеваете, что у bob есть метод name () из-за того, что вы добавили скобки после имени. Однако в этом примере такого метода нет. 'bob.name' (без круглых скобок) напрямую обращается к атрибуту с именем name из метода init (constructor). Когда вызывается метод говори Боба, это метод, который обращается к атрибуту имени и возвращает его в операторе печати. Надеюсь это поможет.
sw123456

3
Нет, вы получаете значение self.name, которое для объекта bob на самом деле является bob.name, потому что имя объекта передается в параметр self при его создании (создании экземпляра). Опять же, надеюсь, это поможет. Не стесняйтесь поднять основной пост, если он есть.
sw123456

2
Имя присваивается self.name при создании экземпляра. После создания объекта все переменные, принадлежащие объекту, имеют префикс «self». Помните, что self заменяется именем объекта при его создании из класса.
sw123456

5
Вот как вы объясняете вещи!
пента

80

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

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: []

18
так что переменные без "я" - это просто статичные переменные класса, как в java
teddy teddy

5
Тедди Тедди, ты не совсем прав. Поведение (как статическое или нестатическое) зависит не только от selfтипа переменной, но и от нее. Попробуйте сделать первый пример с простым целым числом вместо списка. Результат будет совсем другим.
Константин

2
На самом деле, мой вопрос с этим: почему вы можете сказать a.fooв первом примере, а не A.foo? Очевидно, fooпринадлежит к классу ...
Радон Росборо

Вы можете вызывать статические члены из экземпляров объекта на большинстве языков. Почему это удивительно?
Парт

2
@RadonRosborough Потому что в первом примере aи bесть метки (или указатели) для A()(класса). a.fooссылается на A().fooметод класса. Во втором примере, однако, aстановится ссылка на экземпляр из A(), как это делает b. Теперь, когда они являются экземплярами вместо самого объекта класса, self позволяет fooметоду работать с экземплярами.
LegendaryDude

40

Я продемонстрирую с кодом, который не использует классы :

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 )

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


1
Я бы хотел, чтобы Python приукрашивал обработчики так же, как это делает Руби.
Сис Тиммерман

20

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

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

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

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


20

Как и все другие причины, о которых уже говорилось, это упрощает доступ к переопределенным методам; вы можете позвонить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

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


2
class myClass: def myFunc (this, name): this.name = name
LEMUEL ADANE

16

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

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

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

Тем не менее, объектный метод, который требует, чтобы вы сделали переменную, которая является животным, в этом случае нуждается в аргументе 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 "Объектно-ориентированное программирование". Как только вы поймете это, вам даже не нужно будет задавать этот вопрос :).


+1 из-за различия между staticMethod()и objectMethod(self). Я хотел бы добавить, что для того, чтобы вызвать первое, вы бы сказали Animal.staticMethod(), в то время как objectMethod()нужен экземпляр:a = Animal(); a.objectMethod()
Laryx Decidua

То, что вы говорите, не на 100% верно. Это просто соглашение. Вы все еще можете вызвать статический метод из созданного объекта. Вы просто не сможете использовать учеников, потому что не объявили себя. Я даже могу вызвать Animal.objectMethod (animalObj) для вызова нестатического. По сути это означает, что статический метод - это только метод, который не использует переменные-члены. Не должно быть необходимости заявлять о себе. Это глупое требование языка, я думаю. Такие языки, как Lua и C ++, предоставляют вам переменные obj за кулисами.
user441521

Вы сделали бесполезное объявление строки animalName и отказали в методе animalName.
Сис Тиммерман

3
@ytpillai Не имеет значения. Запутанный и неправильный код не должен быть представлен как ответ.
Сис Тиммерман

1
def getAnimalNameчтобы не забивать строку, которую вы пытаетесь вернуть, и selfссылается на экземпляр класса, а не на любое поле внутри него.
Сис Тиммерман

10

Он должен следовать дзену Python «явное лучше, чем неявное». Это действительно ссылка на ваш объект класса. Например, в Java и PHP это называется this.

Если user_type_nameэто поле в вашей модели, вы получаете к нему доступ self.user_type_name.


10

Прежде всего, self - это условное имя, вместо него можно поставить что-нибудь другое (будучи связным).

Он относится к самому объекту, поэтому, когда вы его используете, вы объявляете, что .name и .age являются свойствами объектов Student (обратите внимание, не класса Student), которые вы собираетесь создать.

class Student:
    #called each time you create a new Student instance
    def __init__(self,name,age): #special method to initialize
        self.name=name
        self.age=age

    def __str__(self): #special method called for example when you use print
        return "Student %s is %s years old" %(self.name,self.age)

    def call(self, msg): #silly example for custom method
        return ("Hey, %s! "+msg) %self.name

#initializing two instances of the student class
bob=Student("Bob",20)
alice=Student("Alice",19)

#using them
print bob.name
print bob.age
print alice #this one only works if you define the __str__ method
print alice.call("Come here!") #notice you don't put a value for self

#you can modify attributes, like when alice ages
alice.age=20
print alice

Код здесь


1
Ваш ответ кажется мне наиболее понятным. +1
Павел

9

selfявляется ссылкой на объект самого объекта, следовательно, они одинаковы. Методы Python не вызываются в контексте самого объекта. selfв Python может использоваться для работы с пользовательскими объектными моделями или чем-то еще.


8

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

1: использование самообъяснения

Обратите внимание, что это не ключевое слово.

Первый аргумент каждого метода класса, включая init, всегда является ссылкой на текущий экземпляр класса. По соглашению этот аргумент всегда называется «я». В методе init self ссылается на вновь созданный объект; в других методах класса он ссылается на экземпляр, метод которого был вызван. Например, приведенный ниже код совпадает с приведенным выше кодом.

2: Почему у нас это так и почему мы не можем исключить его в качестве аргумента, такого как Java, и вместо этого иметь ключевое слово

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

Примеры кода:

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

    def objectMethod(self):
        print "This is an object method which needs an instance of a class, and that is what self refers to"

PS : это работает только в Python 3.x.

В предыдущих версиях вы должны явно добавить @staticmethodдекоратор, иначе selfаргумент обязателен.


7

Я удивлен, что никто не воспитал Луа. Lua также использует переменную self, однако она может быть опущена, но все еще используется. C ++ делает то же самое с этим. Я не вижу смысла объявлять «себя» в каждой функции, но вы все равно должны иметь возможность использовать его так же, как вы можете использовать с lua и C ++. Для языка, который гордится своей краткостью, странно, что он требует, чтобы вы объявили переменную self.


6

Взгляните на следующий пример, который четко объясняет цель self

class Restaurant(object):  
    bankrupt = False

    def open_branch(self):
        if not self.bankrupt:
           print("branch opened")

#create instance1
>>> x = Restaurant()
>>> x.bankrupt
False

#create instance2
>>> y = Restaurant()
>>> y.bankrupt = True   
>>> y.bankrupt
True

>>> x.bankrupt
False  

self используется / необходим для различения экземпляров

Источник: самостоятельная переменная в Python объяснил - Pythontips


Да, я думаю, мы знаем, почему используется self, но вопрос в том, почему язык заставляет вас явно объявить это. Многие другие языки не требуют этого, и язык, который гордится своей краткостью, вы могли бы подумать, что они просто дадут вам скрытую переменную для использования, как Lua или C ++ (это).
user441521

3
@ kmario23 Ваш ответ был отсюда: pythontips.com/2013/08/07/the-self-variable-in-python-explained При публикации ответов всегда указывайте авторов оригинала как свои собственные.
geekidharsh

@geekidharsh спасибо, я добавил заметку!
kmario23

5

Дело в том, что при разработке python альтернативы вряд ли будут работать. Python разработан, чтобы позволить методам или функциям быть определенными в контексте, где неявные this(а-ля Java / C ++) или явные @(а-ля ruby) не будут работать. Давайте рассмотрим пример с явным подходом с соглашениями Python:

def fubar(x):
    self.x = x

class C:
    frob = fubar

Теперь fubarфункция не будет работать, так как она будет предполагать, что selfэто глобальная переменная (и в том frobчисле). Альтернативой может быть выполнение методов с замененной глобальной областью действия (где selfнаходится объект).

Неявный подход будет

def fubar(x)
    myX = x

class C:
    frob = fubar

Это будет означать, что myXэто будет интерпретироваться как локальная переменная в fubar(и в frobтоже время). Альтернативой здесь было бы выполнение методов с замененной локальной областью действия, которая сохраняется между вызовами, но это исключило бы возможность использования локальных переменных метода.

Однако текущая ситуация хорошо работает:

 def fubar(self, x)
     self.x = x

 class C:
     frob = fubar

здесь при вызове в качестве метода frobполучит объект, для которого он вызывается через selfпараметр, и fubarвсе еще может быть вызван с объектом в качестве параметра и работать так же ( как я думаю).C.frob


3

В __init__методе self ссылается на вновь созданный объект; в других методах класса он ссылается на экземпляр, метод которого был вызван.

Я, как имя, это просто соглашение , называйте его как хотите! но при его использовании, например, для удаления объекта, вы должны использовать то же имя:, __del__(var)где varиспользовалось в__init__(var,[...])

Вы должны взглянуть clsтоже, чтобы иметь более широкую картину . Этот пост может быть полезным.


3

self действует как текущее имя объекта или экземпляр класса.

# Self explanation.


 class classname(object):

    def __init__(self,name):

        self.name=name
        # Self is acting as a replacement of object name.
        #self.name=object1.name

   def display(self):
      print("Name of the person is :",self.name)
      print("object name:",object1.name)


 object1=classname("Bucky")
 object2=classname("ford")

 object1.display()
 object2.display()

###### Output 
Name of the person is : Bucky
object name: Bucky
Name of the person is : ford
object name: Bucky

1

self неизбежно

Был только вопрос должен selfбыть неявным или явным. Guido van Rossumрешил этот вопрос поговорка selfдолжна остаться .

Так где selfживут?

Если бы мы просто придерживались функционального программирования, нам бы это не понадобилось self. Как только мы входим в ООП Python, мы находимself там.

Вот типичный вариант использования class C использования методаm1

class C:
    def m1(self, arg):
        print(self, ' inside')
        pass

ci =C()
print(ci, ' outside')
ci.m1(None)
print(hex(id(ci))) # hex memory address

Эта программа выведет:

<__main__.C object at 0x000002B9D79C6CC0>  outside
<__main__.C object at 0x000002B9D79C6CC0>  inside
0x2b9d79c6cc0

Так selfдержит адрес памяти экземпляра класса. Цель в selfтом, чтобы содержать ссылку на методы экземпляра и предоставить нам явный доступ к этой ссылке.


Обратите внимание, что есть три различных типа методов класса:

  • статические методы (читай: функции),
  • методы класса,
  • методы экземпляра (упомянуто).

0

из документов ,

Особенность методов заключается в том, что объект экземпляра передается в качестве первого аргумента функции. В нашем примере вызов x.f()в точности эквивалентен MyClass.f(x). В общем, вызов метода со списком из n аргументов эквивалентен вызову соответствующей функции со списком аргументов, который создается путем вставки объекта экземпляра метода перед первым аргументом.

предшествующий этому фрагмент,

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

x = MyClass()


-2

это явная ссылка на объект экземпляра класса.


21
Я не думаю, что это помогает Ричзилле понять причину этого.
Георг Шолли

1
@SilentGhost: ты прибил его. Я впечатлен. если я правильно понимаю: я создаю объект как экземпляр определенного класса, а параметр self ссылается на этот объект? Я понимаю, что self относится неявно к самому классу, но было бы здорово, если бы вы объяснили свой ответ немного подробнее.
dkrynicki
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.