Инкапсуляция. Урок 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
Для имитации сокрытия атрибутов в Python используется соглашение (соглашение – это не синтаксическое правило языка, при желании его можно нарушить), согласно которому, если поле или метод имеют два знака подчеркивания впереди имени, но не сзади, то этот атрибут предусмотрен исключительно для внутреннего пользования:
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
в блоке try приводит к выбросу исключения, так как происходит обращение к еще несуществующему полю, а не потому, что это поле скрыто.
Метод __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’. Если так, то атрибут и соответствующее ему значение добавляется в словарь атрибутов объекта.
self.field1 = value
, так как это приведет к новому рекурсивному вызову метода __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.
Курс с примерами решений практических работ:
pdf-версия, android-приложение
ооп — Что значит инкапсулировать?
В разработке ПО есть два схожих понятия – инкапсуляция и сокрытия информации. Кто-то считает, что это синонимы, кто-то нет, но это не так и важно.
Немного истории: Дэвид Парнас в году эдак 70-м в статье “On the Criteria To Be Used in Decomposing Systems into Modules” впервые ввел понятие сокрытия информации, как ключевого инструмента проектирования. Звучал этот принцип примерно так: декомпозиция системы на модули не должна основываться на анализе блок схем или потоков исполнения. Вместо этого, каждый модуль должен прятать внутри некоторое решение (design decision), предоставляя минимальное количество информации о нем своим клиентам.
Вот небольшой пример.
Допустим, вы разрабатываете ынтырпрайз приложение, которое делает что-то важное. Любое нормальное приложение обычно требует некоторой конфигурации: ну, параметры подключения к БД или серверу, и другую ценную информацию. И вот, матерый артихектор (*) вместе с не менее матерым клиентом просят прочитать конфигурацию из конфигурационного файла.
(*) это не опечатка, пожалуйста, не правьте это!
В процессе разговора с ними вы понимаете, что никто толком не знает, почему читать конфигурацию нужно именно из файла, какой должен быть у него формат и что именно там должно храниться.
Теперь вы становитесь перед выбором: вы можете «размазать» сведения о конфигурации ровным слоем по всему приложению. Каждый компонент, которому нужны некоторые параметры, сам полезет в app config, вытянет оттуда нужные данные, пропарсит xml или json и будет готов служить. С другой стороны, очевидно, что решение о том, где именно хранится конфигурация и в каком формате, может измениться в будущем. Поэтому более вменяемым решением будет скрыть информацию о местоположении и формате конфигурации в одном модуле, например, с помощью классов Configuration
и ConfigurationProvider
. В этом случае, когда (да, именно, «когда», а не «если») требования изменятся, то поменяется лишь реализация класса ConfigurationProvider
, а все остальные пользователи этого класса или конфигурации останутся неизменными. Аналогично, при изменении формата, поменяется тоже только процесс парсинга, а не потребители конфигурации.
Этот пример кажется надуманным, но это не так! Мы довольно часто сталкиваемся с изменчивостью требований, но используем, к сожалению, один из двух подходов:
• Полностью игнорируем возможность изменения требований и делаем все в лоб или
• Создаем супер сложное решение с десятком уровней косвенности, которое должно выдержать изменения требований в любом направлении без изменения кода вообще.
Более же разумный подход находится где-то по середине. Каждый раз, когда я начинаю разработку некоторой фичи, я думаю, сколько кусков в коде придется поменять, если требования или детали реализации существенно изменятся. При этом я не стараюсь свести количество изменений к 1 (ну, типа, если мы следуем SRP, то должно быть только одно место, в случае изменения требованй). Я стараюсь, чтобы этих мест было мало, а изменения были простыми.
Собственно, это и есть суть information hiding и его младшей сестры – инкапсуляции.
Что такое инкапсуляция? — Определение из WhatIs.com
По
- Участник TechTarget
В общем, инкапсуляция — это включение одной вещи в другую, так что включенная вещь не очевидна. Декапсуляция — это удаление или обнаружение того, что ранее было заключено в капсулу.
1) В объектно-ориентированном программировании инкапсуляция — это включение в программный объект всех ресурсов, необходимых для функционирования объекта, — в основном, методов и данных. Говорят, что объект «публикует свои интерфейсы». Другие объекты придерживаются этих интерфейсов, чтобы использовать объект, не заботясь о том, как объект выполняет это. Идея такова: «Не говори мне, как ты это делаешь, просто сделай это». Объект можно рассматривать как автономный атом. Интерфейс объекта состоит из общедоступных методов и экземпляров данных.
2) В электросвязи инкапсуляция — это включение одной структуры данных в другую структуру, так что первая структура данных временно скрыта. Например, пакет данных в формате TCP/IP может быть инкапсулирован в кадр ATM (другой тип передаваемых единиц данных). В контексте передачи и приема кадра ATM инкапсулированный пакет представляет собой просто поток битов между данными ATM, который описывает передачу.
Последнее обновление: апрель 2007 г.
Продолжить чтение Об инкапсуляции- Введение в инкапсуляцию и декапсуляцию в сети
объект
Автор: Петр Лошин
искусственный интеллект вещей (AIoT)
Автор: Александр Гиллис
Hibernate и JDBC: чем отличаются эти API-интерфейсы баз данных?
Автор: Кэмерон Маккензи
Аналитический центр по безопасности: обратите внимание на разрешения доступа к системе на основе атрибутов
Автор: Саймон Персин
ПоискЕдиные Коммуникации
- Как сбалансировать конфиденциальность удаленной работы и мониторинг производительности
Сопоставление мониторинга производительности сотрудников с конфиденциальностью удаленных работников — серьезная проблема, требующая защиты личных . ..
- Как бороться с проблемами безопасности голоса на платформах для совместной работы
Совместная работа на предприятии является неотъемлемой частью ведения бизнеса. Но компании должны научиться защищаться от проблем с безопасностью голоса…
- Microsoft представляет надстройку премиум-класса для собраний Teams
Microsoft планирует выпустить надстройку Teams Premium в феврале, но не будет запускать расширенные возможности искусственного интеллекта до конца года…
SearchMobileComputing
- Вопросы и ответы Jamf: как упрощенная регистрация BYOD помогает ИТ-специалистам и пользователям
Руководители Jamf на JNUC 2022 делятся своим видением будущего с упрощенной регистрацией BYOD и ролью iPhone в …
- Jamf приобретет ZecOps для повышения безопасности iOS
Jamf заплатит нераскрытую сумму за ZecOps, который регистрирует активность на устройствах iOS для выявления потенциальных атак. Компании ожидают …
- Apple преследует растущий премиальный рынок с iPhone 14
Apple переключила свое внимание на смартфоны премиум-класса в последней линейке iPhone 14 с такими функциями, как режим блокировки, который ИТ …
SearchDataCenter
- Лучшие практики оптимизации сети центра обработки данных
Оптимизация сети центра обработки данных может улучшить влияние на бизнес и обеспечить долгосрочную работоспособность оборудования. Посмотрите, чтобы испытать новое оборудование,…
- Советы по созданию стратегии управления воздушным потоком в центре обработки данных
Воздушный поток в центрах обработки данных имеет решающее значение для исправности оборудования. Несмотря на популярность горячего/холодного коридора, рассмотрите другие варианты, такие как …
- Как использовать отчеты файлового сервера в FSRM
Отчеты файлового сервера в диспетчере ресурсов файлового сервера могут помочь администраторам выявлять проблемы, а затем устранять неполадки серверов Windows. ..
ПоискITChannel
- Объем рынка ИТ-услуг вырастет на 7,9% в 2023 году
ИТ-директора в следующем году, скорее всего, снова призовут поставщиков услуг к работе, поскольку они надеются преодолеть разрыв в навыках и …
- Консалтинговая компания EY делает ставку на платформу Nexus для быстрой трансформации
Платформа Nexus призвана помочь клиентам модернизировать ИТ и может стать частью консалтинговой компании EY как отдельной организации; другое …
- Партнеры делают ставку на инструменты для ускоренной цифровой трансформации
Соответствующие инструменты для быстрого отслеживания изменений охватывают отрасль благодаря предложениям таких гигантов профессиональных услуг, как …
Инкапсуляция Определение и значение | Dictionary.com
- Основные определения
- Викторина
- Примеры
[ en-kap-suh-ley-shuhn, -syoo- ]
/ ɛnˌkæp səˈleɪ ʃən, -syʊ- /
Сохранить это слово!
сущ.
действие или процесс помещения или содержания чего-либо внутри или как бы внутри капсулы: Борьба с загрязнением свинцом включает такие стратегии, как удаление краски и инкапсуляция или постоянное покрытие загрязненной почвы. Этот программный протокол используется для инкапсуляции различных протоколов более высокого уровня.
действие или процесс обобщения или сгущения информации: Как автор заголовков, я искал краткое изложение определенных существенных фактов.
ВИКТОРИНА
Сыграем ли мы «ДОЛЖЕН» ПРОТИВ. «ДОЛЖЕН» ВЫЗОВ?
Следует ли вам пройти этот тест на «должен» или «должен»? Это должно оказаться быстрым вызовом!
Вопрос 1 из 6
Какая форма обычно используется с другими глаголами для выражения намерения?
Происхождение инкапсуляции
encapsul(ate) + -ation
Слова рядом с инкапсуляцией
encage, encamp, encampment, encapsulant, encapsulate, encapsulation, encapsule, Encarnación, encarnalize, encarpus, en carré
Dictionary. com Полный текст Основано на словаре Random House Unabridged Dictionary, © Random House, Inc. 2022
Как использовать инкапсуляцию в предложении
То, что может показаться надуманной фантазией, вместо этого воплощает в себе стремление многих автомобильных компаний сегодня.
Как автомобильные компании склоняются к движению осознанности|Энн Кито|17 января 2021|Кварц
В «Вальгалле» есть тихий момент, который лучше всего отражает это.
Как «Assassin’s Creed Valhalla» объясняет истории о викингах, пиратах и Джордже Вашингтоне|Gene Park|1 января 2021|Washington Post
Его имя говорит само за себя, заключая в себе импульс, который привел меня к путешествиям на всю жизнь , как в Соединенных Штатах, так и во всем мире.
Путешествие во время пандемии в компании собак|Уолтер Никлин|18 декабря 2020 г.|Washington Post
Эти меры защиты, закрепленные в Директиве об электронной коммерции, гласят, что «поставщики посреднических услуг» не несут ответственности за незаконные контент, который публикуют их пользователи, при условии, что они быстро удаляют его, как только кто-то отмечает его незаконный характер.