5.1 Уровни доступа
Вы, наверное, обратили внимание на странное имя конструктора __init__? В будущем вы будете встречать такое довольно часто.
В Python существуют различные уровни доступа к атрибутам и методам классов, которые помогают контролировать видимость и защищённость данных. Основные механизмы управления доступом включают использование одного или двух подчёркиваний (_ и __) перед именем атрибута или метода.
Использование соглашений
Одно подчёркивание _ используется для атрибутов и методов, которые не должны использоваться вне класса или модуля. Это не запрещено, но это соглашение, которое следует соблюдать для лучшей читаемости и поддержки кода.
Два подчёркивания __ используются для атрибутов и методов, которые должны быть действительно приватными и защищёнными от случайного или намеренного доступа извне. Механизм name mangling делает их менее доступными, но всё ещё доступными через специальные имена.
Публичные (public) поля и методы
Публичные атрибуты и методы доступны из любого места кода. В Python по умолчанию все атрибуты и методы публичны, если их имена не начинаются с подчёркивания.
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # Доступно
print(obj.public_method()) # Доступно
Через уровни доступа в языке Python реализуется инкапсуляция, а именно через непубличные поля и методы.
5.2 Непубличные поля и методы
Защищённые (protected) поля и методы
Защищённые атрибуты и методы обозначаются одним подчёркиванием _ перед именем и предназначены для внутреннего использования в классе и его подклассах. Это соглашение, которое говорит программистам о том, что данные не предназначены для использования вне класса.
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # Доступно, но не рекомендуется
print(obj._protected_method()) # Доступно, но не рекомендуется
Приватные (private) поля и методы
В Python приватные атрибуты и методы обозначаются двумя подчёркиваниями __ перед именем. Эти атрибуты и методы предназначены для использования исключительно внутри класса, и их основная цель — скрыть внутреннюю реализацию и защитить данные от случайного изменения или использования извне.
Чтобы предотвратить прямой доступ к таким атрибутам и методам из внешнего кода, Python применяет специальный механизм, известный как name mangling (искажение имени). Этот механизм автоматически изменяет имена приватных атрибутов, добавляя к ним префикс, состоящий из имени класса. Таким образом, приватный атрибут __private_attribute в классе MyClass будет преобразован во внутреннее имя _MyClass__private_attribute.
Это позволяет защитить данные от непреднамеренного доступа, сохраняя при этом возможность работы с ними внутри класса. Однако, важно помнить, что механизм "name mangling" не является абсолютной защитой — опытный программист может получить доступ к этим данным, используя изменённое имя.
Давайте рассмотрим, как это работает на практике:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # Ошибка, недоступно напрямую
# print(obj.__private_method()) # Ошибка, недоступно напрямую
print(obj.access_private_method()) # Доступно через публичный метод класса
Как видно из примера, прямой доступ к приватным атрибутам или методам вызывает ошибку. Но Python сохраняет возможность доступа к ним через изменённое имя. Например, вы можете получить доступ к приватному атрибуту с использованием "искажённого" имени, как показано ниже:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # Выведет: I am private
Хотя доступ через "искажённое" имя возможен, этого следует избегать, так как это нарушает принципы инкапсуляции и может привести к нестабильности кода.
Чтобы увидеть, как Python изменяет имена атрибутов, вы можете использовать встроенную функцию dir(), которая отображает все доступные атрибуты и методы объекта:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # Выводит все атрибуты и методы объекта, включая "искажённые" имена
В результате выполнения функции dir() вы увидите список всех атрибутов и методов объекта, включая _MyClass__private_attribute, что подтверждает механизм "name mangling".
5.3 Автоматический вызов методов
Был один интересный аспект при работе с конструкторами, на который вы, возможно, обратили внимание. Метод __init__ вызывался автоматически.
На самом деле таких ситуаций довольно много, как и методов на эти случаи. Примеры:
Метод __str__
Если у вашего объекта есть метод __str__, то он будет вызван автоматически при попытке преобразовать ваш объект в строку, например, при использовании функций print() и str().
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
cat = Cat("Barsik", 5)
print(cat) # Выведет: Barsik is 5 years old
Метод __len__
А если у вашего объекта есть метод __len__, то он будет вызван автоматически при попытке определить «длину» вашего объекта — используется функцией len(). Пример:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # Выведет: 3
Таких «служебных методов» ещё будет много в вашей жизни, но работать с ними одно удовольствие. Так что готовьтесь :)
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ