Инкапсуляция python: Инкапсуляция, наследование, полиморфизм | Python 3 для начинающих и чайников

Содержание

Инкапсуляция. Урок 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 приводит к выбросу исключения, так как происходит обращение к еще несуществующему полю, а не потому, что это поле скрыто. Когда же этому полю присваивается значение 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__() написать просто

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.

Курс с примерами решений практических работ:
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

00035 OBJ1 = DEFIVED ()

OBJ2 = BASE ()

PRINT

PRINT

PRINT (9003

. _a)

Печать ( «Доступ к защищенному члену OBJ2:" , OBJ2._A)

 

class Base:

     def __init__( self ):

 

        

         self ._a = 2

 

class Derived(Base):

     def __init__( self ):

 

        

        

         Base. __init__ ( self )

         print ( "Вызов защищенного члена базового класса: "

6 , 0005

               self ._a)

 

        

         self ._a = 3

         print ( "Calling modified protected член вне класса: " ,

              self ._a)

 

5

9002 . Вызов модифицированного защищенного члена вне класса: 3 Доступ к защищенному элементу obj1: 3 Доступ к защищенному элементу obj2: 2

Закрытые члены

Закрытые члены аналогичны защищенным членам, разница в том, что члены класса, объявленные закрытыми, не должны быть доступны ни извне класса, ни из какого-либо базового класса. В Python не существует переменных экземпляра Private , к которым нельзя получить доступ, кроме как внутри класса.

Однако для определения закрытого члена добавьте к имени члена префикс двойного подчеркивания «__».

Примечание. К закрытым и защищенным членам Python можно получить доступ за пределами класса путем изменения имени python.

Python3

 

 

 

class Base:

     def __init__( self ):

         self .a = "Geeksforgeeks"

Self .__ C = "Geeksforgeeks"

9 "Geeksforgeeks"0034 class Derived(Base):

     def __init__( self ):

 

        

        

         Base. __init__( self )

         print ( "Вызов частного члена базового класса: " ) 3 3 3 

36

print ( self .__c)

 

 

obj1 = Base()

print (obj1.a)

 

 

Вывод:  

 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

Язык кода: Python (python)

Класс Counter имеет один атрибут с именем current , который по умолчанию равен нулю. И у него есть три метода:

  • increment() увеличивает значение текущего атрибута на единицу.
  • value() возвращает текущее значение текущего атрибута
  • reset() устанавливает значение текущего атрибута на ноль.

В следующем примере создается новый экземпляр класса Counter и трижды вызывается метод increment() перед отображением текущего значения счетчика на экране:

 

counter = Counter() счетчик. инкремент() счетчик.инкремент() счетчик.инкремент() печать (счетчик.значение())

Язык кода: Python (python)

Вывод:

 

3

Язык кода: Python (python)

Работает отлично, но есть одна проблема.

Извне класса Counter вы по-прежнему можете получить доступ к текущему атрибуту и ​​изменить его на что угодно. Например:

 

счетчик = счетчик() счетчик.инкремент() счетчик.инкремент() счетчик.ток = -999 печать (счетчик.значение())

Язык кода: Python (python)

Вывод:

 

-999

Язык кода: Python (python)

В этом примере мы создаем экземпляр класса Counter , дважды вызываем метод increment() и устанавливаем для текущего атрибута недопустимое значение -999 .

Так как же предотвратить изменение текущего атрибута за пределами класса Counter ?

Вот почему в игру вступают частные атрибуты.

Частные атрибуты

Частные атрибуты могут быть доступны только из методов класса. Другими словами, они не могут быть доступны извне класса.

В Python нет концепции частных атрибутов. Другими словами, все атрибуты доступны снаружи класса.

По соглашению, вы можете определить закрытый атрибут, добавив одиночное подчеркивание (_):

 

_attribute

Это означает, что _attribute нельзя манипулировать, и в будущем он может быть серьезно изменен.

Следующее переопределяет класс счетчика с текущим как закрытый атрибут по соглашению:

 

class Counter: защита __init__(сам): self. _current = 0 приращение определения (сам): self._current += 1 значение определения (я): вернуть self._current сброс защиты (сам): self._current = 0

Язык кода: Python (python)

Изменение имени с двойным подчеркиванием

Если вы добавляете префикс имени атрибута с двойным подчеркиванием ( __ ), например:

 

__attribute

Python автоматически изменит имя __attribute на:

 

_class__attribute

Делая это, вы не можете получить доступ к __attribute напрямую извне класса, например:

 

instance.__attribute

Язык кода: CSS (css)

Однако вы все еще можете получить к нему доступ, используя _class__attribute имя:

 

instance. _class__attribute

Язык кода: CSS (css)

В следующем примере переопределяется класс Counter с атрибутом __current:

 

class Counter: защита __init__(сам): сам.__текущий = 0 приращение определения (сам): self.__current += 1 значение определения (я): вернуть себя.__текущий сброс защиты (сам): сам.__текущий = 0

Теперь, если вы попытаетесь получить доступ к атрибуту __current, вы получите ошибку:

 

счетчик = счетчик() print(counter.__current)

Язык кода: PHP (php)

Вывод:

 

AttributeError: Объект «Счетчик» не имеет атрибута «__current»

Язык кода: JavaScript (javascript 4022script) 9021 9021 9021 9021 9021 Однако вы можете получить доступ к атрибуту __current как _Counter___current следующим образом:

 

counter = Counter() print(counter. _Counter__current)

Язык кода: PHP (php)

Резюме

  • Инкапсуляция — это упаковка данных и методов в класс, чтобы можно было скрыть информацию и ограничить доступ извне.
  • Добавьте перед атрибутом одиночное подчеркивание ( _ ), чтобы сделать его закрытым по соглашению.
  • Добавьте перед атрибутом двойное подчеркивание ( __ ), чтобы использовать искажение имени.

Считаете ли вы это руководство полезным?

Инкапсуляция в 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. (СУХОЙ – не повторяйтесь).
  • Приложения можно безопасно поддерживать.
  • Обеспечивает гибкость кода за счет правильной организации кода.
  • Обеспечивает удобство работы пользователей, не раскрывая каких-либо внутренних сложностей.
  • Улучшает читаемость кода. Любые изменения в одной части кода не повлияют на другую.

Оставить комментарий