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

Какая область видимости переменной экземпляра класса?

1.0 Junior🔥 201 комментариев
#Python Core

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

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

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

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

Область видимости (scope) переменной экземпляра в Python определяет, где эта переменная доступна для использования. Это один из важных аспектов объектно-ориентированного программирования.

1. Основные уровни видимости в Python

Python имеет четыре уровня видимости (правило LEGB):

  • Local — локальные переменные внутри функции
  • Enclosing — переменные из охватывающей функции (замыкание)
  • Global — глобальные переменные на уровне модуля
  • Built-in — встроенные переменные Python
global_var = "Глобальная"

def outer_func():
    enclosing_var = "Охватывающая"
    
    def inner_func():
        local_var = "Локальная"
        print(local_var)        # Локальная
        print(enclosing_var)    # Охватывающая
        print(global_var)       # Глобальная
    
    inner_func()

outer_func()

2. Переменные экземпляра класса

Переменные экземпляра определяются как атрибуты объекта класса. Они доступны через self:

class Person:
    def __init__(self, name, age):
        # Переменные экземпляра (instance variables)
        self.name = name  # Доступны через self
        self.age = age
    
    def introduce(self):
        # Доступны в методах экземпляра
        print(f"Я {self.name}, мне {self.age}")

person = Person("Иван", 30)
person.introduce()  # Я Иван, мне 30
print(person.name)  # Доступны снаружи класса

3. Область видимости переменных экземпляра

Переменные экземпляра имеют область видимости на уровне объекта:

Доступны:

  • Внутри методов класса через self
  • Снаружи класса через имя переменной объекта
  • В наследниках класса
class Animal:
    def __init__(self, name):
        self.name = name
    
    def get_name(self):
        return self.name

dog = Animal("Бобик")
print(dog.name)  # Бобик (доступно извне)
print(dog.get_name())  # Бобик (доступно внутри)

# Можно изменить извне
dog.name = "Шарик"
print(dog.name)  # Шарик

Не доступны:

  • В статических методах без ссылки на объект
  • В классовых методах (cls) без создания экземпляра

4. Публичные, защищённые и приватные переменные

Python использует соглашения по именованию для обозначения видимости:

class BankAccount:
    def __init__(self, balance):
        # Публичная переменная (convention: public)
        self.owner = "Иван"
        
        # Защищённая переменная (convention: protected)
        self._balance = balance  # Один подчеркиватель
        
        # Приватная переменная (convention: private)
        self.__pin = 1234  # Двойной подчеркиватель
    
    def get_balance(self):
        # Доступна внутри класса
        return self._balance
    
    def verify_pin(self, pin):
        # Доступна внутри класса
        return self.__pin == pin

account = BankAccount(1000)
print(account.owner)      # Иван - доступна
print(account._balance)   # 1000 - доступна (но не рекомендуется)
print(account.__pin)      # AttributeError - не доступна

5. Name Mangling для приватных переменных

При использовании двойного подчеркивания Python выполняет name mangling — преобразование имени:

class Secret:
    def __init__(self):
        self.__secret = "Секрет"

secret = Secret()
# Попытка прямого доступа
try:
    print(secret.__secret)  # AttributeError
except AttributeError:
    print("Приватная переменная не доступна")

# Но Python просто переименовывает переменную
print(secret._Secret__secret)  # Секрет
print(dir(secret))  # Видно _Secret__secret в списке атрибутов

Это не криптографическая защита, а просто соглашение:

class Parent:
    def __init__(self):
        self.__private = "Родитель"

class Child(Parent):
    def __init__(self):
        super().__init__()
        # Не могу использовать self.__private - это будет _Child__private
        self.__private = "Ребенок"
    
    def show(self):
        print(self._Parent__private)  # Родитель (имя mangling)
        print(self._Child__private)   # Ребенок

child = Child()
child.show()

6. Методы и видимость переменных экземпляра

Методы экземпляра — доступны все переменные:

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        # Доступны переменные экземпляра через self
        return 3.14 * self.radius ** 2

circle = Circle(5)
print(circle.area())  # 78.5

Статические методы — не имеют доступа к self:

class Math:
    PI = 3.14  # Переменная класса
    
    def __init__(self, radius):
        self.radius = radius  # Переменная экземпляра
    
    @staticmethod
    def square(x):
        # Не имеет доступа к self.radius
        return x ** 2
    
    def get_area(self):
        # Имеет доступ к self.radius
        return Math.PI * self.radius ** 2

math = Math(5)
print(math.square(3))  # 9
print(math.get_area())  # 78.5

Методы класса — имеют доступ к cls, но не к self:

class Counter:
    count = 0
    
    def __init__(self, name):
        self.name = name
        Counter.count += 1
    
    @classmethod
    def get_count(cls):
        # Доступ к переменной класса
        return cls.count
    
    @classmethod
    def from_string(cls, string):
        # Имеет доступ к cls для создания экземпляра
        name = string.split(':')[0]
        return cls(name)

c1 = Counter("Первый")
c2 = Counter("Второй")
print(Counter.get_count())  # 2

c3 = Counter.from_string("Третий:extra")
print(Counter.get_count())  # 3

7. Переменные класса vs переменные экземпляра

class Book:
    # Переменная класса (общая для всех экземпляров)
    total_books = 0
    
    def __init__(self, title):
        # Переменная экземпляра (уникальна для каждого объекта)
        self.title = title
        Book.total_books += 1

book1 = Book("Python")
book2 = Book("JavaScript")

print(book1.title)         # Python (переменная экземпляра)
print(Book.total_books)    # 2 (переменная класса)
print(book1.total_books)   # 2 (доступна через экземпляр)

# Изменение переменной класса
Book.total_books = 100
print(book1.total_books)   # 100
print(book2.total_books)   # 100

# Изменение переменной экземпляра
book1.title = "Python Pro"
print(book1.title)         # Python Pro
print(book2.title)         # JavaScript (не изменилась)

8. Наследование и область видимости

class Parent:
    def __init__(self):
        self.parent_var = "Родитель"

class Child(Parent):
    def __init__(self):
        super().__init__()
        self.child_var = "Ребенок"
    
    def show_all(self):
        # Доступны переменные обоих классов
        print(self.parent_var)  # Родитель
        print(self.child_var)   # Ребенок

child = Child()
child.show_all()
print(child.parent_var)  # Родитель
print(child.child_var)   # Ребенок

9. Лучшие практики

Используй соглашение по именованию:

class User:
    def __init__(self, email, password):
        # Публичная переменная
        self.email = email
        
        # Защищённая (не трогай извне)
        self._password = password
        
        # Приватная (только для внутреннего использования)
        self.__session_token = None

Используй свойства (properties) вместо прямого доступа:

class Temperature:
    def __init__(self, celsius):
        self._celsius = celsius
    
    @property
    def celsius(self):
        return self._celsius
    
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Температура ниже абсолютного нуля")
        self._celsius = value

temp = Temperature(25)
print(temp.celsius)      # 25
print(temp.fahrenheit)   # 77
temp.celsius = 30
print(temp.fahrenheit)   # 86

Итог: Переменные экземпляра в Python доступны через self внутри методов и напрямую через имя объекта извне. Используй соглашения с подчеркиваниями для обозначения приватности: публичные (name), защищённые (_name), приватные (__name). Name mangling — это не настоящая защита, а просто соглашение для разработчиков.

Какая область видимости переменной экземпляра класса? | PrepBro