Python - Модификаторы доступа

Привет, стремящиеся к программированию на Python! Сегодня мы отправляемся в захватывающее путешествие в мир модификаторов доступа в Python. Не волнуйтесь, если вы новичок в программировании; я веду вас по этой концепции шаг за шагом, с множеством примеров и пояснений по пути. Поехали!

Python - Access Modifiers

Модификаторы доступа в Python

В объектно-ориентированном программировании модификаторы доступа используются для управления видимостью и доступом к членам класса (атрибутам и методам). В то время как многие языки программирования имеют строгие модификаторы доступа, такие как public, private и protected, Python следует более спокойному подходу. Он следует философии, часто называемой "Мы все согласны здесь взрослые".

В Python у нас есть три типа модификаторов доступа:

  1. Public
  2. Protected
  3. Private

Давайте рассмотрим каждый из них с примерами.

Public Members

В Python все члены являются публичными по умолчанию. Это означает, что они могут быть доступны извне класса. Вот пример:

class Student:
def __init__(self, name, age):
self.name = name  # Public attribute
self.age = age    # Public attribute

def display_info(self):  # Public method
print(f"Name: {self.name}, Age: {self.age}")

# Создание экземпляра Student
student1 = Student("Alice", 20)

# Доступ к публичным членам
print(student1.name)  # Output: Alice
student1.display_info()  # Output: Name: Alice, Age: 20

В этом примере name, age и display_info() все являются публичными членами. Мы можем получить к ним доступ напрямую извне класса.

Protected Members

Защищенные члены обозначены префиксом с одной подчеркивательной (_). Они не являются действительно приватными и могут быть доступны извне класса, но это соглашение о том, что их следует рассматривать только для внутреннего использования.

class Employee:
def __init__(self, name, salary):
self._name = name      # Protected attribute
self._salary = salary  # Protected attribute

def _display_salary(self):  # Protected method
print(f"{self._name}'s salary is ${self._salary}")

# Создание экземпляра Employee
emp1 = Employee("Bob", 50000)

# Доступ к защищенным членам (Обратите внимание: Это возможно, но не рекомендуется)
print(emp1._name)  # Output: Bob
emp1._display_salary()  # Output: Bob's salary is $50000

Хотя мы можем получить доступ к _name, _salary и _display_salary(), обычно не рекомендуется делать это извне класса или его подклассов.

Private Members

Приватные члены обозначены префиксом с двумя подчеркивательными (__). Python выполняет изменение имен для этих членов, делая их сложнее (но не невозможно) доступными извне класса.

class BankAccount:
def __init__(self, account_number, balance):
self.__account_number = account_number  # Private attribute
self.__balance = balance                # Private attribute

def __display_balance(self):  # Private method
print(f"Balance: ${self.__balance}")

def public_display(self):
self.__display_balance()

# Создание экземпляра BankAccount
account1 = BankAccount("123456", 1000)

# Попытка доступа к приватным членам
# print(account1.__account_number)  # Это вызовет AttributeError
# account1.__display_balance()      # Это также вызовет AttributeError

# Доступ к приватному методу через публичный метод
account1.public_display()  # Output: Balance: $1000

В этом примере, __account_number, __balance и __display_balance() являются приватными членами. Попытка доступа к ним напрямую извне класса вызовет AttributeError.

Изменение имен

Помните, когда я упомянул, что приватные члены в Python не являются действительно приватными? Это из-за механизма, называемого изменением имен. Когда вы создаете приватный член с двумя подчеркивательными, Python изменяет его имя внутри, чтобы сделать его сложнее доступным случайно.

Вот как это работает:

class NameManglingDemo:
def __init__(self):
self.__private_var = "Я приватный!"

demo = NameManglingDemo()
print(dir(demo))
# Output: [..., '_NameManglingDemo__private_var', ...]

# Доступ к приватной переменной с помощью измененного имени
print(demo._NameManglingDemo__private_var)  # Output: Я приватный!

Как вы видите, Python переименовывает __private_var в _NameManglingDemo__private_var. Это изменение имен в действии!

Объект свойства Python

Функция property() в Python является встроенной функцией, которая создает и возвращает объект свойства. Это способ добавить методы getter, setter и deleter к атрибутам класса.

Вот пример:

class Temperature:
def __init__(self, celsius):
self._celsius = celsius

def get_fahrenheit(self):
return (self._celsius * 9/5) + 32

def set_fahrenheit(self, fahrenheit):
self._celsius = (fahrenheit - 32) * 5/9

fahrenheit = property(get_fahrenheit, set_fahrenheit)

# Использование свойства
temp = Temperature(25)
print(temp.fahrenheit)  # Output: 77.0

temp.fahrenheit = 86
print(temp._celsius)  # Output: 30.0

В этом примере fahrenheit является свойством, которое позволяет нам получать и устанавливать температуру в Фаренгейтах, храня ее внутри в Цельсиях.

Методы Getter и Setter

Методы getter и setter используются для получения и установки значений атрибутов класса. Они предоставляют способ доступа и изменения приватных атрибутов, сохраняя энкapsulation.

Вот пример с использованием декоратора @property, который является более питоническим способом реализации getter и setter:

class Person:
def __init__(self, name, age):
self._name = name
self._age = age

@property
def name(self):
return self._name

@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("Имя должно быть строкой")
self._name = value

@property
def age(self):
return self._age

@age.setter
def age(self, value):
if not isinstance(value, int) or value < 0:
raise ValueError("Возраст должен быть положительным целым")
self._age = value

# Использование getter и setter
person = Person("Charlie", 30)
print(person.name)  # Output: Charlie

person.name = "David"
print(person.name)  # Output: David

try:
person.age = -5
except ValueError as e:
print(e)  # Output: Возраст должен быть положительным целым

В этом примере мы создали getter и setter для name и age. Методы setter включают валидацию, чтобы убедиться, что значения, которые устанавливаются, соответствуют определенным критериям.

Для подведения итогов рассмотренным методам, вот таблица в формате Markdown:

Метод Описание Пример
Public Доступен из любого места self.name
Protected Доступен внутри класса и подклассов (по соглашению) self._name
Private Имя изменено для ограничения доступа self.__name
Property Создает объект свойства property(get_method, set_method)
Getter Метод для получения значения атрибута @property
Setter Метод для установки значения атрибута @attribute.setter

И это всё! Мы покрыли модификаторы доступа в Python, изменение имен, объекты свойства и методы getter и setter. Помните, подход Python к управлению доступом больше основан на соглашениях и доверии, чем на строгих правилах. Когда вы продолжаете свое путешествие по Python, вы обнаружите, что эта гибкость позволяет писать чистый и читаемый код, сохраняя при этом способность реализовывать энкapsulation при необходимости.

Постарайтесь, будьте любознательными и счастливого кодирования!

Credits: Image by storyset