Ответ
В Python инкапсуляция — это в первую очередь соглашение, а не строгое правило, как в Java или C++. Она реализуется с помощью следующих механизмов:
-
Соглашения об именовании (префиксы
_и__):- Одинарное подчеркивание (
_): Сигнализирует, что атрибут или метод является защищенным (protected) и предназначен для внутреннего использования в классе или его наследниках. Технически доступ к нему не ограничен.class MyClass: def __init__(self): self._internal_var = 10 -
Двойное подчеркивание (
__): Делает атрибут или метод приватным (private) с помощью механизма Name Mangling. Python изменяет имя атрибута, добавляя к нему имя класса (_ClassName__attribute), что затрудняет случайный доступ извне.class MyClass: def __init__(self): self.__private_var = 20 obj = MyClass() # print(obj.__private_var) # AttributeError print(obj._MyClass__private_var) # Так доступ возможен
- Одинарное подчеркивание (
-
Свойства (
@property): Декоратор@propertyпозволяет управлять доступом к атрибутам класса, превращая методы в атрибуты, доступные только для чтения. С помощью декораторов@<name>.setterи@<name>.deleterможно добавить логику для записи и удаления, например, для валидации данных.Пример с валидацией:
class BankAccount: def __init__(self, initial_balance): if initial_balance < 0: raise ValueError("Начальный баланс не может быть отрицательным") self.__balance = initial_balance @property def balance(self): """Геттер для получения баланса.""" return self.__balance @balance.setter def balance(self, value): """Сеттер с валидацией для изменения баланса.""" if value < 0: raise ValueError("Баланс не может быть отрицательным") self.__balance = value account = BankAccount(100) print(account.balance) # 100 (работает геттер) account.balance = 200 # OK (работает сеттер) # account.balance = -50 # Вызовет ValueErrorТакой подход позволяет скрыть внутреннюю реализацию (
__balance) и предоставить безопасный публичный интерфейс (balance).
Ответ 18+ 🔞
Ну и вот, смотри, как у нас в Питоне с этой вашей инкапсуляцией дела обстоят. Не то чтобы её совсем нет, но она тут, блядь, больше на честном слове держится, а не на железобетонных правилах, как у этих зануд из Java. Тут всё через договорённости и хитрые уловки.
Первое — это договорняки по именам, с подчёркиваниями.
Один знак (_) — это типа намёк, мол, чувак, не лезь сюда, это для внутренней кухни. Но технически-то ты можешь, конечно, сука, залезть. Просто все понимают, что ты мудак, если полез.
class MyClass:
def __init__(self):
self._internal_var = 10 # Ну типа не трогай, а то в глаз получишь
А вот два знака (__) — это уже посерьёзнее, это Name Mangling, ёпта! Питон такой: "Ах, ты хочешь приватности? Щас я тебе имя так исковеркаю, что только мать родная узнает!" Он прилепляет спереди имя класса, и получается _MyClass__private_var. Снаружи просто так уже не достучишься, хотя, если очень хочется, то можно, блядь, всё.
class MyClass:
def __init__(self):
self.__private_var = 20 # Попробуй, сука, достань теперь!
obj = MyClass()
# print(obj.__private_var) # Ошибка, нихуя не найдёт
print(obj._MyClass__private_var) # А вот так — пожалуйста, на тебе! Хитрый жополиз.
Второе — это свойства, @property, вообще магия, блядь!
С их помощью можно прикинуться просто атрибутом, а на самом деле внутри будет целая опера с геттерами и сеттерами. Идеально, чтобы спрятать свою жопу и не давать кому попало менять твои внутренние переменные.
Вот смотри, пример с банковским счётом, а то эти пользователи вечно норовят баланс в минус увести, пидарасы!
class BankAccount:
def __init__(self, initial_balance):
if initial_balance < 0:
raise ValueError("Начальный баланс не может быть отрицательным, ты чё, охренел?")
self.__balance = initial_balance # Спрятано, как золото в сейфе
@property
def balance(self):
"""Геттер. Посмотреть можно, а тронуть — нет."""
return self.__balance
@balance.setter
def balance(self, value):
"""Сеттер. Тут мы, блядь, проверяем, не долбоёб ли ты."""
if value < 0:
raise ValueError("Баланс не может быть отрицательным, ебаный рот!")
self.__balance = value
account = BankAccount(100)
print(account.balance) # 100 — работает геттер, всё ок
account.balance = 200 # 200 — сеттер пропустил, молодец
# account.balance = -50 # А вот тут, сука, получишь ValueError прямо в ебальник!
Вот так и живём: снаружи красивый интерфейс, а внутри — вся логика, валидация и крики "чё блядь?!" на неправильные данные. Инкапсуляция по-питонячьи, ёпта!