← Назад к вопросам

Зачем в __init__ передается ссылка на первым параметром?

1.6 Junior🔥 141 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем в init передается ссылка на первым параметром?

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

Понимание self

class Person:
    def __init__(self, name, age):
        # self — это ссылка на конкретный объект
        self.name = name  # Сохраняем имя в атрибут объекта
        self.age = age    # Сохраняем возраст в атрибут объекта
        print(f"Создан объект Person: {id(self)}")
    
    def introduce(self):
        # self используется для доступа к атрибутам объекта
        return f"Привет, я {self.name}, мне {self.age} лет"

# При создании объекта
person1 = Person("Иван", 30)  # Печатает: Создан объект Person: 140342851234512
person2 = Person("Мария", 25)  # Печатает: Создан объект Person: 140342851234560

print(person1.introduce())  # self = person1 -> "Привет, я Иван, мне 30 лет"
print(person2.introduce())  # self = person2 -> "Привет, я Мария, мне 25 лет"

Как Python передает self автоматически

class Counter:
    def __init__(self, start=0):
        self.value = start
    
    def increment(self):
        self.value += 1

# Когда мы пишем:
counter = Counter(10)
counter.increment()

# Python делает следующее:
# 1. counter = Counter(10)
#    -> Python создает новый объект
#    -> Python передает его как self в __init__
#    -> self = <объект Counter>
#    -> self.value = 10

# 2. counter.increment()
#    -> Python передает counter как self в метод increment
#    -> self = counter
#    -> self.value += 1
#    -> counter.value становится 11

print(counter.value)  # 11

Без self (как это работало бы без Python)

# ❌ КАК БЫ БЫЛ БЕЗ PYTHON (НИЗКОУРОВНЕВЫЙ КОД)

class PersonWithoutSelf:
    pass

# Если бы пришлось передавать объект вручную
person = PersonWithoutSelf()

# Пришлось бы передавать объект во все методы
def init(obj, name, age):
    obj.name = name
    obj.age = age

def introduce(obj):
    return f"Привет, я {obj.name}, мне {obj.age} лет"

# Использование
init(person, "Иван", 30)
print(introduce(person))  # Очень неудобно!

# ✅ С PYTHON И self (ВЫСОКОУРОВНЕВЫЙ КОД)

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def introduce(self):
        return f"Привет, я {self.name}, мне {self.age} лет"

# Использование
person = Person("Иван", 30)
print(person.introduce())  # Намного удобнее!

self хранит состояние объекта

class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner      # Атрибут объекта
        self.balance = balance  # Атрибут объекта
    
    def deposit(self, amount):
        self.balance += amount  # Изменяем состояние THIS объекта
    
    def withdraw(self, amount):
        if self.balance >= amount:
            self.balance -= amount
        else:
            print("Недостаточно средств")

# Каждый объект имеет свое состояние
account1 = BankAccount("Иван", 1000)
account2 = BankAccount("Мария", 2000)

account1.deposit(500)   # self = account1, balance становится 1500
account2.withdraw(200)  # self = account2, balance становится 1800

print(account1.balance)  # 1500 (состояние account1)
print(account2.balance)  # 1800 (состояние account2)
print(account1 is account2)  # False (разные объекты)

self явно и неявно

class Student:
    def __init__(self, name, grade):
        # ЯВНОЕ использование self
        self.name = name
        self.grade = grade
    
    def get_info(self):
        # ЯВНОЕ использование self
        return f"{self.name} ({self.grade} класс)"
    
    def study(self):
        # НЕЯВНОЕ использование self
        # Python передаёт self автоматически
        print(f"{self.name} учится")

# Явное (через точку)
student = Student("Петр", 10)
print(student.get_info())  # Python передает student как self

# Явное (через класс)
Student.get_info(student)  # Можно вызвать метод класса, явно передав объект
print(Student.get_info(student))  # Петр (10 класс)

Различие между переменной экземпляра и локальной переменной

class Example:
    def __init__(self, value):
        # self.value — ПЕРЕМЕННАЯ ЭКЗЕМПЛЯРА (атрибут объекта)
        # Доступна везде в объекте
        self.value = value
        
        # local_var — ЛОКАЛЬНАЯ ПЕРЕМЕННАЯ
        # Существует только в этом методе
        local_var = value * 2
        print(local_var)  # 20 (если value = 10)
    
    def show_value(self):
        # Можно обратиться к self.value
        print(self.value)  # Работает (100)
        
        # Но local_var недоступна
        # print(local_var)  # NameError: name 'local_var' is not defined

example = Example(10)
example.show_value()  # Печатает 10

# Доступ к переменной экземпляра снаружи
print(example.value)  # 10 (доступна через объект)

self в разных контекстах

class Calculator:
    def __init__(self, initial=0):
        self.result = initial
    
    def add(self, x):
        self.result += x
        return self  # Возвращаем self для цепочки вызовов
    
    def multiply(self, x):
        self.result *= x
        return self  # Для паттерна Method Chaining
    
    @classmethod
    def from_string(cls, value_str):
        # В classmethod используется cls, а не self
        return cls(int(value_str))
    
    @staticmethod
    def is_positive(x):
        # В staticmethod нет ни self, ни cls
        return x > 0

# Использование
calc = Calculator(10)
result = calc.add(5).multiply(2).add(10)
print(calc.result)  # 40 (10 + 5 = 15, 15 * 2 = 30, 30 + 10 = 40)

# classmethod
calc2 = Calculator.from_string("20")  # cls = Calculator
print(calc2.result)  # 20

# staticmethod
print(Calculator.is_positive(5))  # True (не требует объекта)

Сравнение self в разных языках

# PYTHON
class Python:
    def method(self):
        print(self)  # self — явно указано

# JAVA / C# / C++ — this
public class Java {
    public void method() {
        System.out.println(this);  // this — явно указано (но скрыто по умолчанию)
    }
}

# JAVASCRIPT — this
class JavaScript {
    method() {
        console.log(this);  // this — явно указано
    }
}

# В Python self ОБЯЗАТЕЛЕН в параметрах,
# в других языках это часто неявно

Ошибки с self

# ❌ Ошибка 1: забыли self
class WrongClass:
    def __init__(name, age):  # Забыли self!
        name = name
        age = age

obj = WrongClass("Иван", 30)
# TypeError: __init__() takes 2 positional arguments but 3 were given
# "Иван" становится self, а 30 становится name!

# ✅ Правильно
class RightClass:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# ❌ Ошибка 2: использовали self в staticmethod
class WrongStatic:
    @staticmethod
    def static_method(self, x):  # НЕПРАВИЛЬНО!
        return self.x  # AttributeError

# ✅ Правильно
class RightStatic:
    @staticmethod
    def static_method(x):  # Никакого self
        return x * 2

print(RightStatic.static_method(5))  # 10

# ❌ Ошибка 3: забыли вызвать метод через объект
class MyClass:
    def __init__(self):
        self.value = 10
    
    def get_value(self):
        return self.value

obj = MyClass()
# MyClass.get_value()  # TypeError: get_value() missing 1 required positional argument: 'self'
# Нужно передать объект
obj.get_value()  # Правильно
# или MyClass.get_value(obj)  # Тоже правильно

Заключение

self — это фундаментальный механизм Python, который позволяет:

  1. Получить доступ к состоянию объекта — каждый экземпляр имеет свои атрибуты
  2. Вызывать другие методы объекта — self.method()
  3. Различать объекты — self указывает на конкретный объект

При создании экземпляра класса Python автоматически передает созданный объект как первый параметр в метод. Это позволяет методам работать с состоянием именно этого объекта, а не какого-то другого. Без self объектно-ориентированное программирование в Python было бы невозможно.