Инкапсуляция. Урок 6 курса “Объектно-ориентированное программирование на Python”
Под инкапсуляцией в объектно-ориентированном программировании понимается упаковка данных и методов для их обработки вместе, т. е. в классе. В Python инкапсуляция реализуется как на уровне классов, так и объектов. В ряде других языков, например в Java, под инкапсуляцией также понимают сокрытие свойств и методов, в результате чего они становятся приватными. Это значит, что доступ к ним ограничен либо пределами класса, либо модуля.
В Python подобной инкапсуляции нет, хотя существует способ ее имитировать. Перед тем как выяснять, как это делается, надо понять, зачем вообще что-то скрывать.
Дело в том, что классы бывают большими и сложными. В них может быть множество вспомогательных полей и методов, которые не должны использоваться за его пределами. Они просто для этого не предназначены. Они своего рода внутренние шестеренки, обеспечивающие нормальную работу класса.
Кроме того, в других языках программирования хорошей практикой считается сокрытие всех полей объектов, чтобы уберечь их от прямого присвоения значений из основной ветки программы.
Например, если надо проверять присваиваемое полю значение на корректность, то делать это каждый раз в основном коде программы будет неправильным. Проверочный код должен быть помещен в метод, который получает данные для присвоения полю. А само поле должно быть закрыто для доступа из вне класса. В этом случае ему невозможно будет присвоить недопустимое значение.
Часто намеренно скрываются поля самого класса, а не его объектов. Например, если класс имеет счетчик своих объектов, то необходимо исключить возможность его случайного изменения из вне. Рассмотрим пример с таким счетчиком на языке Python.
class B:
count = 0
def __init__(self):
B.count += 1
def __del__(self):
B.count -= 1
a = B()
b = B()
print(B.count) # выведет 2
del a
print(B.count) # выведет 1Все работает. В чем тут может быть проблема? Проблема в том, что если в основной ветке где-то по ошибке или случайно произойдет присвоение полю B.
count, то счетчик будет испорчен:
… B.count -= 1 print(B.count) # выведет 0, хотя остался b
class B:
__count = 0
def __init__(self):
B.__count += 1
def __del__(self):
B.__count -= 1
a = B()
print(B.__count)Попытка выполнить этот код приведет к выбросу исключения:
...
print(B.__count)
AttributeError: type object 'B' has no
attribute '__count'То есть атрибут __count за пределами класса становится невидимым, хотя внутри класса он вполне себе видимый. Понятно, если мы не можем даже получить значение поля за пределами класса, то присвоить ему значение – тем более.
На самом деле сокрытие в Python не настоящее и доступ к счетчику мы получить все же можем.
Но для этого надо написать B._B__count:
… print(B._B__count)
Таково соглашение. Если в классе есть атрибут с двумя первыми подчеркиваниями, то для доступа извне к имени атрибута добавляется имя класса с одним впереди стоящим подчеркиванием. В результате атрибут как он есть (в данном случае __count) оказывается замаскированным. Вне класса такого атрибута просто не существует. Для программиста же наличие двух подчеркиваний перед атрибутом должно сигнализировать, что трогать его вне класса не стоит вообще, даже через _B__count, разве что при крайней необходимости.
Хорошо, мы защитили поле от случайных изменений. Но как теперь получить его значение? Сделать это можно с помощью добавления метода:
class B:
__count = 0
def __init__(self):
B.__count += 1
def __del__(self):
B.__count -= 1
def qty_objects():
return B.__count
a = B()
b = B()
print(B.qty_objects()) # выведет 2В данном случае метод qty_object() не принимает объект (нет self’а), поэтому вызывать его надо через класс.
То же самое с методами. Их можно сделать “приватными” с помощью двойного подчеркивания:
class DoubleList:
def __init__(self, l):
self.double = DoubleList.__make_double(l)
def __make_double(old):
new = []
for i in old:
new.append(i)
new.append(i)
return new
nums = DoubleList([1, 6, 12])
print(nums.double)
print(DoubleList.__make_double([1, 2]))Результат:
[1, 1, 6, 6, 12, 12]
Traceback (most recent call last):
...
print(DoubleList.__make_double([1, 2]))
AttributeError: type object 'DoubleList'
has no attribute '__make_double'В одном из комментариев к предыдущим версиям данного курса был приведен пример, согласно которому скрытые поля при присваивании им становятся открытыми:
class Full:
def __init__(self, field):
self.__field = field
def setField(self, field):
self.
__field = field
def getField(self):
return self.__field
obj = Full(8)
obj.setField(3)
print(obj.getField())
try:
print(obj.__field)
except AttributeError:
print("Нет атрибута __field")
obj.__field = 5
print(obj.__field)Результат выполнения:
3 Нет атрибута __field 5
На самом деле в данном примере поле экземпляра __field, определенное за пределами класса, – это совсем другое поле. Не тот __field, который находится в классе и обращаться к которому из вне надо с помощью _Full__field. В этом можно убедиться, если вывести на экран содержимое атрибута __dict__:
... print(obj.__dict__) obj.__field = 5 print(obj.__dict__) print(obj.__field is obj._Full__field)
Результат:
...
{'_Full__field': 3}
{'_Full__field': 3, '__field': 5}
FalseПоэтому в коде выше выражение obj.__field
Когда же этому полю присваивается значение 5, то у объекта появляется новое поле.Метод __setattr__()
В Python атрибуты объекту можно назначать за пределами класса:
>>> class A: ... def __init__(self, v): ... self.field1 = v ... >>> a = A(10) >>> a.field2 = 20 >>> a.field1, a.field2 (10, 20)
Если такое поведение нежелательно, его можно запретить с помощью метода перегрузки оператора присваивания атрибуту __setattr__():
>>> class A: ... def __init__(self, v): ... self.field1 = v ... def __setattr__(self, attr, value): ... if attr == 'field1': ... self.__dict__[attr] = value ... else: ... raise AttributeError ... >>> a = A(15) >>> a.field1 15 >>> a.field2 = 30 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 8, in __setattr__ AttributeError >>> a.field2 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'A' object has no attribute 'field2' >>> a.__dict__ {'field1': 15}
Поясним, что здесь происходит. Метод __setattr__(), если он присутствует в классе, вызывается всегда, когда какому-либо атрибуту выполняется присваивание. Обратите внимание, что присвоение несуществующему атрибуту также обозначает его добавление к объекту.
Когда создается объект a, в конструктор передается число 15. Здесь для объекта заводится атрибут field1. Факт попытки присвоения ему значения тут же отправляет интерпретатор в метод __setattr__(), где проверяется соответствует ли имя атрибута строке ‘field1’. Если так, то атрибут и соответствующее ему значение добавляется в словарь атрибутов объекта.
Нельзя в __setattr__() написать просто , так как это приведет к новому рекурсивному вызову метода __setattr__(). Поэтому поле назначается через словарь __dict__, который есть у всех объектов, и в котором хранятся их атрибуты со значениями.
Если параметр attr не соответствует допустимым полям, то искусственно возбуждается исключение AttributeError. Мы это видим, когда в основной ветке пытаемся обзавестись полем field2.
Если объект содержит скрытые поля и к ним происходит обращение из __setattr__(), то делать это надо так, как будто обращение происходит не из класса. Следующий код приведет к генерации исключения:
class A:
def __init__(self, x):
self.__x = x
def __setattr__(self, attr, value):
if attr == "__x":
self.__dict__[attr] = value
else:
raise AttributeError
a = A(5)Результат:
Traceback (most recent call last):
File "...2.py", line 12, in <module>
a = A(5)
File "...2.py", line 3, in __init__
self.__x = x
File "...2.py", line 9, in __setattr__
raise AttributeError
AttributeErrorВ методе __setattr__() параметр attr – это имя свойства экземпляра в том виде, в котором оно находится в словаре __dict__.
Если свойство скрытое, то в __dict__ оно будет записано через имя класса. Поэтому в данном случае правильный код будет таким:
class A:
def __init__(self, x):
self.__x = x
def __setattr__(self, attr, value):
if attr == "_A__x":
self.__dict__[attr] = value
else:
raise AttributeErrorПрактическая работа
Разработайте класс с “полной инкапсуляцией”, доступ к атрибутам которого и изменение данных реализуются через вызовы методов. В объектно-ориентированном программировании принято имена методов для извлечения данных начинать со слова get (взять), а имена методов, в которых свойствам присваиваются значения, – со слова set (установить). Например, get_field, set_field.
Курс с примерами решений практических работ:
android-приложение, pdf-версия
Python | Инкапсуляция, атрибуты и свойства
Последнее обновление: 26.01.2022
По умолчанию атрибуты в классах являются общедоступными, а это значит, что из любого места программы мы можем получить атрибут объекта и изменить его.
Например:
class Person:
def __init__(self, name):
self.name = name # устанавливаем имя
self.age = 1 # устанавливаем возраст
def display_info(self):
print(f"Имя: {self.name}\tВозраст: {self.age}")
tom = Person("Tom")
tom.name = "Человек-паук" # изменяем атрибут name
tom.age = -129 # изменяем атрибут age
tom.display_info() # Имя: Человек-паук Возраст: -129
Но в данном случае мы можем, к примеру, присвоить возрасту или имени человека некорректное значение, например, указать отрицательный возраст. Подобное поведение нежелательно, поэтому встает вопрос о контроле за доступом к атрибутам объекта.
С данной проблемой тесно связано понятие инкапсуляции. Инкапсуляция является фундаментальной концепцией объектно-ориентированного программирования. Она предотвращает прямой доступ к атрибутам объект из вызывающего кода.
Касательно инкапсуляции непосредственно в языке программирования Python скрыть атрибуты класса можно сделав их приватными или закрытыми и ограничив доступ к ним через специальные методы,
которые еще называются свойствами.
Изменим выше определенный класс, определив в нем свойства:
class Person:
def __init__(self, name):
self.__name = name # устанавливаем имя
self.__age = 1 # устанавливаем возраст
def set_age(self, age):
if 1 < age < 110:
self.__age = age
else:
print("Недопустимый возраст")
def get_age(self):
return self.__age
def get_name(self):
return self.__name
def display_info(self):
print(f"Имя: {self.__name}\tВозраст: {self.__age}")
tom = Person("Tom")
tom.display_info() # Имя: Tom Возраст: 1
tom.set_age(-3486) # Недопустимый возраст
tom.set_age(25)
tom.display_info() # Имя: Tom Возраст: 25
Для создания приватного атрибута в начале его наименования ставится двойной прочерк: self.__name. К такому атрибуту мы сможем обратиться только из того же класса.
Но не сможем обратиться вне этого класса. Например, присвоение значения этому атрибуту ничего не даст:
tom.__age = 43
Потому что в данном случае просто определяется динамически новый атрибут __age, но это он не имеет ничего общего с атрибутом self.__age.
А попытка получить его значение приведет к ошибке выполнения (если ранее не была определена переменная __age):
print(tom.__age)
Однако все же нам может потребоваться устанавливать возраст пользователя из вне. Для этого создаются свойства. Используя одно свойство, мы можем получить значение атрибута:
def get_age(self):
return self.__age
Данный метод еще часто называют геттер или аксессор.
Для изменения возраста определено другое свойство:
def set_age(self, age):
if 1 < age < 110:
self.__age = age
else:
print("Недопустимый возраст")
Данный метод еще называют сеттер или мьютейтор (mutator).
Здесь мы уже можем решить в зависимости от условий, надо ли переустанавливать возраст.
Необязательно создавать для каждого приватного атрибута подобную пару свойств. Так, в примере выше имя человека мы можем установить только из конструктора. А для получение определен метод get_name.
Аннотации свойств
Выше мы рассмотрели, как создавать свойства. Но Python имеет также еще один – более элегантный способ определения свойств. Этот способ предполагает использование аннотаций, которые предваряются символом @.
Для создания свойства-геттера над свойством ставится аннотация @property.
Для создания свойства-сеттера над свойством устанавливается аннотация имя_свойства_геттера.setter.
Перепишем класс Person с использованием аннотаций:
class Person:
def __init__(self, name):
self.__name = name # устанавливаем имя
self.__age = 1 # устанавливаем возраст
@property
def age(self):
return self.
__age
@age.setter
def age(self, age):
if 1 < age < 110:
self.__age = age
else:
print("Недопустимый возраст")
@property
def name(self):
return self.__name
def display_info(self):
print(f"Имя: {self.__name}\tВозраст: {self.__age}")
tom = Person("Tom")
tom.display_info() # Имя: Tom Возраст: 1
tom.age = -3486 # Недопустимый возраст
print(tom.age) # 1
tom.age = 36
tom.display_info() # Имя: Tom Возраст: 36
Во-первых, стоит обратить внимание, что свойство-сеттер определяется после свойства-геттера.
Во-вторых, и сеттер, и геттер называются одинаково – age. И поскольку геттер называется age, то над сеттером устанавливается аннотация @age.setter.
После этого, что к геттеру, что к сеттеру, мы обращаемся через выражение tom.age.
НазадСодержаниеВперед
Инкапсуляция Python, наследование, полиморфизм – Русские Блоги
Инкапсуляция Python, наследование, полиморфизм
Теги: Python
Каталог статей
- Инкапсуляция Python, наследование, полиморфизм
- Три характеристики объектно-ориентированного подхода:
- Один, пакет
- 1.
Определение - 2. Объектно-ориентированный и процессно-ориентированный
- Во-вторых, наследование
- 1. Определение
- Три, полиморфизм
- 1. Определение
Инкапсуляция Python, наследование, полиморфизм
Три характеристики объектно-ориентированного подхода:
Инкапсуляция: помещайте свойства и методы внутри класса, получайте доступ к свойствам или методам через объекты, скрывайте процесс реализации функций, конечно, вы также можете установить права доступа
Наследование: подклассам необходимо повторно использовать свойства или методы в родительском классе, конечно, подкласс также может предоставлять свои собственные свойства и методы.
Полиморфизм: разные объекты в одном методе вызывают одну и ту же функцию метода в разных формах,
Один, пакет
1. Определение
Суть инкапсуляции заключается в инкапсуляции свойств и методов, связанных с вещами в классе.
Когда мы вызываем класс для создания экземпляра, нам не нужно заботиться о деталях реализации внутреннего кода класса. Это эквивалентно черному ящику. Нам нужен только экземпляр (черный ящик) Было бы неплохо дать желаемый результат.
2. Объектно-ориентированный и процессно-ориентированный
class person:
def __init__(self, new_name, new_age):
self.name = new_name
self.age = new_age
def __str__(self):
return "Возраст% s% d" % (self.name, self.age)
def listen(self):
print("Слушая музыку")
def movie(self):
print("Смотрю фильм")
def introduce(self):
print("Возраст% s% d" % (self.name, self.age))
M = person("Сяо Мин", 18)
H = person("Немного красный", 16)
print(M)
print(M.listen(), M.movie(), M.introduce())
print("==============================")
print(H)
print(H.listen(), H.movie(), H.introduce())
Здесь объект не может напрямую вызвать метод.
- Лицом к процессу: все переменные и методы открыты
Во-вторых, наследование
1.
ОпределениеНаследование означает, что дочерний класс наследует свойства и методы родительского класса.
Три, полиморфизм
1. Определение
Один и тот же метод, разные объекты вызывают этот метод, реализованные функции разные
Самый наглядный пример – это метод работы “+” в python:
При сложении чисел 1 + 2 = 3, что является сложением в обычном смысле, но, ‘a’ + ‘b’ = ‘ab’, является конкатенацией строк, используемых в списке: [1] + [2 ] = [1, 2], это сплайсинг списка, одно и то же имя метода, используемое для разных объектов, выполняет совершенно разные функции, это полиморфизм;
Интеллектуальная рекомендация
Несколько вопросов о справочных указателях 2018-06-15
Указатель по умолчанию под дугой является сильная ссылка: __ SICK & __ слабое и __ небезопасное сравнение ссылка:__strong & __weak & __ Unsafe_unreted…
Pytorch использует больше средств GPU
Использование нескольких графических процессоров в Pytorch требует инициализации заявленной модели после Декларационной модели, такой как: Затем, после запуска файла Python The Model Training, все GPU.
..
Как долго это так долго? Как логистические роботы не побежали на тысячи домохозяйств?
В заключенных ЦЕС Группа «Немецкая континентальная группа демонстрирует свои последние логистические роботы» – собака доставки пакетов Anymal. Для этого результат Круг медиа и технологичес…
Примечания к практическому изучению машинного обучения — алгоритм априори
Анализ ассоциаций – это задача поиска интересных взаимосвязей в крупномасштабных наборах данных. Эти отношения могут принимать две формы: Частые наборы элементов: набор элементов, которые часто появля…
Spring (4) Фреймворк заключительной главы третьей интеграции
Spring_day04 (интеграция трех основных фреймворков) 1. Три фреймворка (принцип интеграции) Бэкэнд веб-проекта разделен на три слоя. 2. Направляющий пакет (42) hibernate: hibernate/lib/required hiberna…
Вам также может понравиться
Первое понимание юнит-теста серии Python
Среду модульного тестирования unittest можно применять не только для модульного тестирования, но и для разработки и выполнения веб-автоматизированных тестовых примеров.
Конструктура тестирования может …
Принцип непоследовательной загрузки изображений в процессе загрузки изображений в виде списка.
// Основная раскладка интерфейса // Вложенный макет // Основная функция MainActivity // Создать новый класс бина // Создать адаптер // Инструменты…
SpringBoot + mysql + развертывание проекта docker
Подготовка доменного имени и сервера Alibaba Cloud доменное имя: Вы можете приобрести необходимые доменные имена у основных поставщиков облачных услуг. Я приобрел доменное имя Alibaba Cloud. В облако …
Строить IPA-сервер с нуля. Реализация LDAP + Kerberos домена Проверка (Open Firewall, Command Version)
Рисунок метод конфигурации, пожалуйста, обратитесь к статье 1, экспериментальная среда: Физика хост-хост две виртуальные машины. Физический IP хост: 192.168.9.6/24 GW: 192.168.9.254 DNS: 8.8.8.8 Вирту…
Вызов клиента Центра конфигурации Apollo
Вызов клиента Центра конфигурации Apollo введение Центр конфигурации Создать проект Опубликовать пространство имен Создайте файл конфигурации локального кеша код проекта springboot Предыдущая запись: .
..
Инкапсуляция в Python – GeeksforGeeks
Инкапсуляция — одна из фундаментальных концепций объектно-ориентированного программирования (ООП). Он описывает идею упаковки данных и методы, которые работают с данными в одном блоке. Это накладывает ограничения на прямой доступ к переменным и методам и может предотвратить случайное изменение данных. Чтобы предотвратить случайное изменение, переменная объекта может быть изменена только методом объекта. Эти типы переменных известны как частные переменные .
Класс является примером инкапсуляции, так как он инкапсулирует все данные, которые являются функциями-членами, переменными и т. д.
Рассмотрим пример инкапсуляции из реальной жизни. , финансовый отдел, отдел продаж и т. д. Финансовый раздел обрабатывает все финансовые операции и ведет учет всех данных, связанных с финансами. Точно так же отдел продаж обрабатывает все действия, связанные с продажами, и ведет учет всех продаж. Сейчас может возникнуть ситуация, когда чиновнику из финансового отдела по каким-то причинам нужны все данные о продажах в конкретном месяце.
В этом случае ему не разрешается прямой доступ к данным раздела продаж. Сначала ему придется связаться с другим сотрудником отдела продаж, а затем попросить его предоставить конкретные данные. Вот что такое инкапсуляция. Здесь данные отдела продаж и сотрудников, которые могут ими манипулировать, объединены одним названием «отдел продаж». Использование инкапсуляции также скрывает данные. В этом примере данные таких разделов, как продажи, финансы или счета, скрыты от любого другого раздела.
Защищенные члены
Защищенные члены (в C++ и JAVA) — это те члены класса, к которым нельзя получить доступ за пределами класса, но к которым можно получить доступ внутри класса и его подклассов. Чтобы выполнить это в Python, просто следуйте соглашению , добавляя к имени члена префикс одинарного подчеркивания «_» .
Хотя к защищенной переменной можно получить доступ из класса, а также в производном классе (также измененном в производном классе), общепринято (соглашение, а не правило) не обращаться к защищенной переменной из тела класса.
Примечание: Метод __init__ является конструктором и запускается, как только создается экземпляр объекта класса.
Python3
0005 |
Закрытые члены
Закрытые члены аналогичны защищенным членам, разница в том, что члены класса, объявленные закрытыми, не должны быть доступны ни извне класса, ни из какого-либо базового класса. В Python не существует переменных экземпляра Private , к которым нельзя получить доступ, кроме как внутри класса.
Однако для определения закрытого члена добавьте к имени члена префикс двойного подчеркивания «__».
Примечание. К закрытым и защищенным членам Python можно получить доступ за пределами класса путем изменения имени python.
Python3
"Geeksforgeeks"0034 |
Вывод:
GeeksforGeeks
Трассировка (последний последний вызов): Файл "/home/f4905b43bfcf29567e360c709d3c52bd.py", строка 25, впечать(obj1.c) AttributeError: объект «Base» не имеет атрибута «c» Traceback (последний последний вызов): Файл "/home/4d97a4efe3ea68e55f48f1e7c7ed39cf.py", строка 27, в obj2 = Производный() Файл "/home/4d97a4efe3ea68e55f48f1e7c7ed39cf. py", строка 20, в __init__ печать (я.__с) AttributeError: «Производный» объект не имеет атрибута «_Derived__c»
Четкое понимание инкапсуляции Python на практических примерах
Резюме : в этом руководстве вы узнаете об инкапсуляции и о том, как использовать частные атрибуты для выполнения инкапсуляции в Python.
Введение в инкапсуляцию в Python
Инкапсуляция — это одна из четырех фундаментальных концепций объектно-ориентированного программирования, включая абстракцию, инкапсуляцию, наследование и полиморфизм.
Инкапсуляция — это упаковка данных и функций, которые работают с этими данными, в одном объекте. Тем самым вы можете скрыть внутреннее состояние объекта от внешнего. Это известно как сокрытие информации .
Класс является примером инкапсуляции. Класс объединяет данные и методы в единое целое. А класс предоставляет доступ к своим атрибутам через методы.
Идея сокрытия информации заключается в том, что если у вас есть атрибут, который не виден извне, вы можете контролировать доступ к его значению, чтобы убедиться, что ваш объект всегда находится в допустимом состоянии.
Давайте рассмотрим пример, чтобы лучше понять концепцию инкапсуляции.
Пример инкапсуляции Python
Следующее определяет класс Counter :
защита __init__(сам):
собственный ток = 0
приращение определения (сам):
собственный ток += 1
значение определения (я):
вернуть self.current
сброс защиты (сам):
собственный ток = 0
Класс Counter имеет один атрибут с именем current , который по умолчанию равен нулю. И у него есть три метода:
-
increment()увеличивает значение текущего атрибутана единицу. -
value()возвращает текущее значениетекущего атрибута -
reset()устанавливает значение текущего атрибутана ноль.
В следующем примере создается новый экземпляр класса Counter и трижды вызывается метод increment() перед отображением текущего значения счетчика на экране:
Язык кода: Python (python)
counter = Counter() счетчик.инкремент() счетчик.инкремент() счетчик.инкремент() печать (счетчик.значение())
Вывод:
Язык кода: Python (python)
3
Работает отлично, но есть одна проблема.
Извне класса Counter вы по-прежнему можете получить доступ к текущему атрибуту и изменить его на что угодно. Например:
Язык кода: Python (python)
счетчик = счетчик() счетчик.инкремент() счетчик.инкремент() счетчик.ток = -999 печать (счетчик.значение())
Вывод:
Язык кода: Python (python)
-999
В этом примере мы создаем экземпляр класса Counter , дважды вызываем метод increment() и устанавливаем для текущего атрибута недопустимое значение -999 .
Так как же предотвратить изменение текущего атрибута за пределами класса Counter ?
Вот почему в игру вступают частные атрибуты.
Частные атрибуты
Частные атрибуты могут быть доступны только из методов класса. Другими словами, они не могут быть доступны извне класса.
В Python нет концепции частных атрибутов. Другими словами, все атрибуты доступны снаружи класса.
По соглашению, вы можете определить закрытый атрибут, добавив одиночное подчеркивание (_):
_attribute
Это означает, что _attribute нельзя манипулировать, и в будущем он может быть серьезно изменен.
Следующее переопределяет класс счетчика с текущим как закрытый атрибут по соглашению:
Язык кода: Python (python)
class Counter: защита __init__(сам): self._current = 0 приращение определения (сам): self._current += 1 значение определения (я): вернуть self._current сброс защиты (сам): self._current = 0
Изменение имени с двойным подчеркиванием
Если вы добавляете префикс имени атрибута с двойным подчеркиванием ( __ ), например:
__attribute
Python автоматически изменит имя __attribute на:
_class__attributeДелая это, вы не можете получить доступ к __attribute напрямую извне класса, например:
Язык кода: CSS (css)
instance.__attributeОднако вы все еще можете получить к нему доступ, используя _class__attribute имя:
Язык кода: CSS (css)
instance._class__attribute
В следующем примере переопределяется класс Counter с атрибутом __current:
class Counter: защита __init__(сам): сам.__текущий = 0 приращение определения (сам): self.__current += 1 значение определения (я): вернуть себя.__текущий сброс защиты (сам): сам.__текущий = 0Теперь, если вы попытаетесь получить доступ к атрибуту __current, вы получите ошибку:
Язык кода: PHP (php)
счетчик = счетчик() print(counter.__current)Вывод:
Язык кода: JavaScript (javascript 4022script) 9021 9021 9021 9021 9021 Однако вы можете получить доступ к атрибуту __current как _Counter___current следующим образом:
AttributeError: Объект «Счетчик» не имеет атрибута «__current»Язык кода: PHP (php)
counter = Counter() print(counter._Counter__current)
Резюме
- Инкапсуляция — это упаковка данных и методов в класс, чтобы можно было скрыть информацию и ограничить доступ извне.
- Добавьте перед атрибутом одиночное подчеркивание (
_), чтобы сделать его закрытым по соглашению.- Добавьте перед атрибутом двойное подчеркивание (
__), чтобы использовать искажение имени.Считаете ли вы это руководство полезным?
Инкапсуляция в Python — AskPython
При работе с объектно-ориентированным языком программирования, таким как Python, инкапсуляция в Python является одной из 4 важных концепций для понимания. Остальные три — это наследование, полиморфизм и абстракция.
Что такое инкапсуляция?
При работе с классами и конфиденциальными данными предоставление глобального доступа ко всем переменным, используемым в программе, не является хорошим выбором. Инкапсуляция предлагает нам способ доступа к требуемым переменным, не предоставляя программе полноценный доступ к любой из этих переменных.
Обновление, изменение или удаление данных из переменных можно выполнить с помощью методов, определенных специально для этой цели. Преимуществом использования такого подхода к программированию является улучшенный контроль над входными данными и повышенная безопасность.
Что такое инкапсуляция в Python?
Концепция инкапсуляции одинакова во всех объектно-ориентированных языках программирования. Разница видна, когда концепции применяются к конкретным языкам.
По сравнению с такими языками, как Java, которые предлагают модификаторы доступа (открытые или закрытые) для переменных и методов, Python обеспечивает глобальный доступ ко всем переменным и методам.
Посмотрите приведенную ниже демонстрацию того, как легко получить доступ к переменным.
класс Лицо: def __init__(я, имя, возраст=0): self.name = имя возраст = возраст дисплей защиты (я): распечатать(я.имя) распечатать (я.возраст) человек = человек('Разработчик', 30) #доступ с использованием метода класса человек.дисплей() #доступ напрямую извне печать(человек.имя) печать(человек.возраст)
Выход
Дев 30 Дев 30Поскольку у нас нет модификаторов доступа в Python, мы будем использовать несколько различных методов для управления доступом к переменным в программе Python.
Методы управления доступом
Python предлагает несколько методов для ограничения доступа к переменным и методам в программе. Пройдемся по методам подробнее.
Использование одиночного подчеркивания
Обычное соглашение программирования Python для идентификации частной переменной заключается в добавлении к ней префикса подчеркивания. На самом деле это не имеет никакого значения для компилятора. Переменная по-прежнему доступна, как обычно. Но, будучи соглашением, которое подхватили программисты, оно сообщает другим программистам, что переменные или методы должны использоваться только в рамках класса.
См. пример ниже:
класс Человек: def __init__(я, имя, возраст=0): self.name = имя self._age = возраст дисплей защиты (я): распечатать(я.имя) печать (я._возраст) человек = человек('Разработчик', 30) #доступ с использованием метода класса человек.дисплей() #доступ напрямую извне печать(человек.имя) печать (человек._возраст)
Выход
Дев 30 Дев 30Понятно, что доступ к переменной не изменился. Но можем ли мы сделать что-нибудь, чтобы действительно сделать его частным? Посмотрим дальше.
Использование двойных символов подчеркивания
Если вы хотите сделать члены класса, т. е. методы и переменные, закрытыми, вы должны добавить к ним двойные символы подчеркивания. Но Python предлагает некоторую поддержку модификатора private. Этот механизм называется Изменение имени . При этом по-прежнему возможен доступ к членам класса извне.
Изменение имени
В Python любой идентификатор с __Var перезаписывается интерпретатором Python как _Classname__Var, а имя класса остается текущим именем класса.
Этот механизм смены имен называется Изменение имени в Python.
В приведенном ниже примере в Class person переменная age изменена, и перед ней стоят двойные подчеркивания в начале.
класс Лицо: def __init__(я, имя, возраст=0): self.name = имя self.__age = возраст дисплей защиты (я): распечатать(я.имя) печать (я.__возраст) человек = человек('Разработчик', 30) #доступ с использованием метода класса человек.дисплей() #доступ напрямую извне print('Попытка доступа к переменным вне класса') печать(человек.имя) печать(человек.__возраст)Выход
Дев 30 Попытка доступа к переменным вне класса Дев Traceback (последний последний вызов): Файл «Person.py», строка 16, впечать(человек.__возраст) AttributeError: объект "Person" не имеет атрибута "__age" Вы можете заметить, что доступ к переменным по-прежнему осуществляется с помощью методов, которые являются частью класса.
Но вы не можете получить доступ к возрасту напрямую извне, так как это частная переменная.
Использование методов Getter и Setter для доступа к закрытым переменным
Если вы хотите получить доступ к закрытым переменным и изменить их, следует использовать методы доступа (геттера) и мутаторы (методы установки), поскольку они являются частью класса.
класс Лицо: def __init__(я, имя, возраст=0): self.name = имя self.__age = возраст дисплей защиты (я): распечатать(я.имя) печать (я.__возраст) защита getAge (я): печать (я.__возраст) def setAge (я, возраст): self.__age = возраст человек = человек('Разработчик', 30) #доступ с использованием метода класса человек.дисплей() # изменение возраста с помощью сеттера person.setAge(35) человек.getAge()Выход
Дев 30 35Преимущества инкапсуляции в Python
Инкапсуляция не только обеспечивает лучший поток данных, но и защищает данные от внешних источников.
Концепция инкапсуляции делает код самодостаточным. Это очень полезно на уровне реализации, так как отдает приоритет вопросам типа «как», оставляя позади сложности. Вы должны скрыть данные в блоке, чтобы упростить инкапсуляцию, а также защитить данные.
Зачем нужна инкапсуляция в Python
Следующие причины показывают, почему разработчики считают инкапсуляцию удобной и почему объектно-ориентированная концепция превосходит многие языки программирования.
- Инкапсуляция помогает добиться четкого взаимодействия в каждом приложении.
- Объектно-ориентированная концепция фокусируется на повторном использовании кода в Python. (СУХОЙ – не повторяйтесь).
- Приложения можно безопасно поддерживать.
- Обеспечивает гибкость кода за счет правильной организации кода.
- Обеспечивает удобство работы пользователей, не раскрывая каких-либо внутренних сложностей.
- Улучшает читаемость кода. Любые изменения в одной части кода не повлияют на другую.
![]()

__field = field
def getField(self):
return self.__field
obj = Full(8)
obj.setField(3)
print(obj.getField())
try:
print(obj.__field)
except AttributeError:
print("Нет атрибута __field")
obj.__field = 5
print(obj.__field)
field2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has
no attribute 'field2'
>>> a.__dict__
{'field1': 15}
__age
@age.setter
def age(self, age):
if 1 < age < 110:
self.__age = age
else:
print("Недопустимый возраст")
@property
def name(self):
return self.__name
def display_info(self):
print(f"Имя: {self.__name}\tВозраст: {self.__age}")
tom = Person("Tom")
tom.display_info() # Имя: Tom Возраст: 1
tom.age = -3486 # Недопустимый возраст
print(tom.age) # 1
tom.age = 36
tom.display_info() # Имя: Tom Возраст: 36
Определение
__init__ (
_a)
__init__(
py", строка 20, в __init__
печать (я.__с)
AttributeError: «Производный» объект не имеет атрибута «_Derived__c»
инкремент()
счетчик.инкремент()
счетчик.инкремент()
печать (счетчик.значение())
_current = 0
приращение определения (сам):
self._current += 1
значение определения (я):
вернуть self._current
сброс защиты (сам):
self._current = 0
_class__attribute
_Counter__current) 
дисплей()
#доступ напрямую извне
печать(человек.имя)
печать(человек.возраст)
name = имя
self._age = возраст
дисплей защиты (я):
распечатать(я.имя)
печать (я._возраст)
человек = человек('Разработчик', 30)
#доступ с использованием метода класса
человек.дисплей()
#доступ напрямую извне
печать(человек.имя)
печать (человек._возраст)
Этот механизм смены имен называется Изменение имени в Python.
Но вы не можете получить доступ к возрасту напрямую извне, так как это частная переменная.
Концепция инкапсуляции делает код самодостаточным. Это очень полезно на уровне реализации, так как отдает приоритет вопросам типа «как», оставляя позади сложности. Вы должны скрыть данные в блоке, чтобы упростить инкапсуляцию, а также защитить данные.