Инкапсуляция — ограничение доступа к составляющим объект компонентам (методам и переменным). Инкапсуляция делает некоторые из компонент доступными только внутри класса.
Инкапсуляция в Python работает лишь на уровне соглашения между программистами о том, какие атрибуты являются общедоступными, а какие — внутренними.
Одиночное подчеркивание в начале имени атрибута говорит о том, что переменная или метод не предназначен для использования вне методов класса, однако атрибут доступен по этому имени.
class Person:
class Person: def __init__(self, name = 'Серега'): self.name = name self._age = 20 инкапсуляция на уровне соглашения protected, с одним нижним подеркиванием def _private(self): print("Это приватный метод, по соглашению!") per = Person('Петя') print(per._age) # Свойство доступно, но по соглашению его использовать не рекомендуется
Двойное подчеркивание в начале имени атрибута даёт большую защиту: атрибут становится недоступным по этому имени.
class Person: def __init__(self, name = 'Серега'): self.name = name self.__age = 20 # инкапсуляция типа private def __private(self): print("Это приватный метод!") per = Person('Петя') print(per.__age) # Свойство недоступно
Однако полностью это не защищает, так как атрибут всё равно остаётся доступным под именем _ИмяКласса__ИмяАтрибута:
print(per._Person__age) #Обход инкапсуляции, доступ к private свойтсву
класс Person
class Person: def __init__(self, name = 'Серега'): self.name = name self.__age = 20 # инкапсуляция типа private def getAge(self): ''' Доступ к private свойствам ''' return self.__age def setAge(self, age): ''' Доступ к private свойствам :param age передаваемый папраметр ''' if age in range(20, 80): self.__age = age else: self.__age = 25
Использоание геттеров и сеттеров:
per = Person('Петя') per.setAge(39) print(per.getAge())
Результат:
>>> 39
класс Person:
Декораторы необходисо создовать в определенной последовательности, сначала getter потом setter. В противном случае Python выкинет исключение и сообщение об ошибке.
class Person: def __init__(self, name = 'Серега'): self.name = name self.__age = 20 # инкапсуляция типа private @property def age(self): ''' Декоратор :param age передаваемый папраметр ''' return self.__age @age.setter def age(self, value): ''' Декоратор :param value передаваемый папраметр ''' self.__age = value
Обращение к закрытым своствам через декоратор
per.age = 36 # Обращение к закрытым свайствам через декоратор setter print(per.age) # Обращение к закрытым свайствам через декоратор getter
Результат:
>>> 36
Наследование подразумевает то, что дочерний класс содержит все атрибуты родительского класса, при этом некоторые из них могут быть переопределены или добавлены в дочернем. Например, мы можем создать свой класс, похожий на словарь:
>>> class Mydict(dict): ... def get(self, key, default = 0): ... return dict.get(self, key, default) ... >>> a = dict(a=1, b=2) >>> b = Mydict(a=1, b=2)
Класс Mydict ведёт себя точно так же, как и словарь, за исключением того, что метод get по умолчанию возвращает не None, а 0.
>>> b['c'] = 4 >>> print(b) {'a': 1, 'c': 4, 'b': 2} >>> print(a.get('v')) None >>> print(b.get('v')) 0
Полиморфизм - разное поведение одного и того же метода в разных классах. Например, мы можем сложить два числа, и можем сложить две строки. При этом получим разный результат, так как числа и строки являются разными классами.
>>> 1 + 1 2 >>> "1" + "1" '11'