Что такое self в Python?

Совсем непонятно, что такое self. Понятно, что его по умолчанию нужно писать как первый параметр описании каждого метода. То есть определение уже наизусть выучил, но трудно понять что оно значит. Вроде никаких затруднений пока что ни с чем больше нет, только с этим. Уже давно ищу, что это такое.
  • Вопрос задан
  • 139819 просмотров
Решения вопроса 1
Defman21
@Defman21
Легко нагуглил.
stackoverflow.com/a/21366809/3307167 - по мне так самый понятный вариант.
stackoverflow.com/a/31096552/3307167 - а тут картиночки даже есть, для лучшего понимания.
Ответ написан
Пригласить эксперта
Ответы на вопрос 9
@olegshv
SysAdmin
Объяснение self в python:

dog‎: у котов внутри есть мурчалка
dog‎: она реализована для всех котов в классе кот
‎dog‎: в объекте кот надо как то вызвать метод мурчало у класса кот
‎dog‎: как ты это сделаешь?
dog‎: кот.мурчало()
‎dog‎: ежели ты вызовешь кот.мурчало(), муркнут сразу все коты на свете
‎dog‎: а ежели ты вызовешь self.мурчало(), муркнет только тот кот, на которого указывает self
Ответ написан
SolidlSnake
@SolidlSnake
Ваш дружелюбный сосед
Аналог слова this из других языков.
В Python «Явное лучше неявного» поэтому его необходимо задавать так конкретно.
Ссылается на конкретный экземпляр класса, а не на класс в целом.
Ответ написан
self - это ни в коем случае не зарезервированное слово. Это просто название переменной.

В методах класса первый параметр функции по соглашению именуют self, и это ссылка на сам объект этого класса. Но это именно соглашение. Вы вольны называть параметры как угодно.

Зачем это нужно?

Ну вот есть объект и вы хотите создать/изменить поле у этого объекта из метода этого самого объекта.

class Human:
    def __init__(self):
        self.blood = 7000

    def add_blood(self, volume):
        self.blood += volume
Ответ написан
@Vovanchick
И все равно ничего не понятно
Ответ написан
@Jhenka
Я думаю, для понимания self нужно обратиться к static.

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

В языке Object Pascal приписка self приписывается автоматически (неявно) к переменным класса. То есть её ставить не надо.

Можно рассматривать класс, как табличку с инструкцией для создания объектов и придания им свойств. Если перед переменой (полем) класса ничего не стоит, значит перед ней неявно присутствует self (в Object Pascal). Такая переменная НЕ меняется в классе (табличке с инструкцией), а присваивается конкретному объекту. То есть такая self переменная в классе (табличке с инструкцией) не изменяется. Чтобы переменная изменилась и в самом классе, нужно перед переменной поставить static. И она будет меняться уже и в самом классе (на той самой пресловутой табличке с инструкцией). Static используют, например, для подсчёта количества созданных объектов. Для этого к static переменной при создании объекта попросту добавляют 1 (единичку). Через конструктор, например. Каждый новый объект будет в результате своего создания добавлять к static переменной ещё одну единичку.

Но это в Object Pascal.

А в Python всё почти что наоборот. Все переменные (поля) класса изначально статичные static (неявно). А чтобы переменную сделать динамической (переменной объекта) то есть self, её просто нужно задать в каком-нибудь методе класса в аргументах. Метод _init_, мне кажется, подойдёт. И назвать, так чтобы она отражала свою сущность – ‘self’ или ‘my_object ‘ (отсылка, что переменная изменяется в объекте, а не в самом классе)

Вот как то так
Ответ написан
Комментировать
@Mori_sad
Автор вопроса, плиз ответь мне, таже самая проблема что и у тебя, не понимаю как этот self работает (((
Ответ написан
@Yareeek192
self - это обращение именно к объекту,
class Human:
def __init__(self):
self.blood = 7000
self - выступает простым обращением к объекту.
x.blood = 7000 - можно присвоить конкретно этому объекту любое другое значение, например: x.blood = 6500.
соответсвенно и при вызове оно будет изменено
можно ничего не менять и если просто написать, то оно выдаст значение по умолчанию.
>>>x.blood
7000
Ответ написан
Комментировать
@kosta_skull
Была та же проблема. Я понял для себя так:

Как мы знаем, для вызова метода необходим такой синтаксис:

something.my_method(a, b, ...)
где something - это объект класса MyClass.

Когда мы описываем(создаем) класс MyClass, в котором нам нужно прописать метод my_method, то мы пишем

class MyClass:
    def my_method(self,  a, b, ...):

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

По этой причине мы можем вызвать тот же метод другим синтаксисом:

MyClass.my_method(something, a, b, ...)

Результат будет такой же, как и при

something.my_method(a, b, ...)

Следующий слой понимания и ответа на вопрос: А зачем?

Допустим, у нашего объекта есть атрибут age, хранящий какое-то численное значение (например, 3). Это значение сделаем общим для всех создаваемых объектов этого класса. Мы хотим, чтобы написанный нами метод брал это значение и умножал на 2. Делаем мы это так

class MyClass:
    age = 3
    def my_method(self):
        return self.age * 2


Теперь создадим объект something класса MyClass и посмотрим, чему равен атрибут age

something = MyClass()

print(something.age)
#Вывод: 3


Теперь посмотрим результат работы нашего метода

print(something.my_method())

#Вывод: 6


Теперь при вызове something.my_method() будет возвращено значение something.age*2, то есть 3*2=6

Мы во второй строке указали age = 3. Значение атрибута age будет в этом случае равнятся 3 для всех объектов этого класса, которые мы будем создавать. Но что, если мы хотим указывать age отдельно для каждого объекта?

Есть специальный метод __init__. Именно с таким именем. Напишете по-другому - не сработает. Он пишется в самом начале описания класса и его параметры задаются в скобках при создании объекта, то есть, вызов этого метода включен в процесс создание объекта класса автоматически. Сейчас на примере. Допустим, мы хотим, чтобы в нашем объекте было два атрибута: age, len. Атрибут age мы будем указывать при создании класса, а len будет считаться автоматически, и будет равен age*2.

class MyClass:
    def __init__(self, age):
        self.age = age
        self.len = age*2


теперь нам нужно будет при создании объекта something задать параметр age:

something = MyClass(6)

чему равны атрибуты age и len?
print(something.age)
print(something.len)

#Вывод:
#6
#12


При создании объекта класса, синтаксис
something = MyClass(a, b, ...)
работает аболютно так же, как
MyClass.__init__(something, a, b, ...)

Сам новичок в ООП, так что могу что-то не так понять и вообще написать не сработающий код, так что жду комментов и предложений
Ответ написан
Комментировать
Сам очень долго не мог понять, но сейчас стал немного понимать, хотя наверное и не до конца. Может кому-то мое объяснение поможет.

Вот код с leetcode к вот этой задаче:
Там нужно сложить два числа, записанные в строках, без всяких int и выдать результат также в str.

class Solution(object):
    def addStrings(self, num1, num2):
        len1 = len (num1)
        len2 = len (num2)
        z1 = 0
        z2 = 0
        for i in range(len1):
            last1 = ord(num1[i]) - 48
            next1 = z1 * 10
            z1 = last1 + next1
        for i in range(len2):
            last2 = ord(num2[i]) - 48
            next2 = z2 * 10
            z2 = last2 + next2     
        return str(z1 + z2)


Дальше вызываем его с разными данными

p = Solution()
print(p.addStrings('192','312'))   # 504
print(p.addStrings('193','312'))   # 505
print(p.addStrings('001','100'))   # 101


Т.е. "p" как был встала после "p = Solution()" на место "self", а после этого уже можно подставлять разные данные и получать результат.

А что, если попытаться обратиться к классу напрямую, не создавая объекта p (который стал self'ом) ? Это глупо и неправильно, но попробуем.

print (Solution.addStrings('32','532'))

И получаем ошибку:
TypeError: Solution.addStrings() missing 1 required positional argument: 'num2'


Пайтон посчитал первое значение - "33" как название объекта (мы же класс создали, а в нем должен быть объект!) , второе значение "532" как первое значение внутренней функции addStrings и говорит - а где второе-то значение???

Если опять же протупить и сделать все неправильно не создавая объект, то можно все же получить результат

print (Solution.addStrings('p2','111','111'))

Выдаст нам правильный результат - "222", но объект с именем "p2" не был создан.

Если мы запросим после этого тип "p" и "p2", то получим такой ответ

print (type(p)) 
#<class '__main__.Solution'>

print (type(p2)) 
NameError: name 'p2' is not defined
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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