Uploaded by Olimjon Yalgashev

8

advertisement
DASTURLASH TILIDA KLASSLAR. INKAPSULYASIYA.
MEROSHORLIK. POLIMORFIZM.
План
1. Инкапсуляция
2. Наследование
3. Полиморфизм
4. Виртуальная функция
1. Инкапсуляция
Инкапсуляция - одна из четырех фундаментальных концепций
объектно-ориентированного программирования, включая абстракцию,
инкапсуляцию, наследование и полиморфизм.
Инкапсуляция - это упаковка данных и функций, которые работают с
этими данными, в одном объекте. Тем самым вы можете скрыть внутреннее
состояние объекта извне. Это называется сокрытием информации.
Класс - это пример инкапсуляции. Класс объединяет данные и методы в
единое целое. А класс предоставляет доступ к своим атрибутам через методы.
Идея сокрытия информации заключается в том, что если у вас есть
атрибут, который не виден снаружи, вы можете контролировать доступ к его
значению, чтобы убедиться, что ваш объект всегда находится в допустимом
состоянии.
Рассмотрим пример, чтобы лучше понять концепцию инкапсуляции.
Следующее определяет класс Counter:
class Counter:
def __init__(self):
self.current = 0
def increment(self):
self.current += 1
def value(self):
return self.current
def reset(self):
self.current = 0
У класса Counter есть один атрибут под названием current, который по
умолчанию равен нулю. И у него есть три метода:
 increment() увеличивает значение текущего атрибута на единицу.
 value() возвращает текущее значение текущего атрибута
 reset() устанавливает значение текущего атрибута равным нулю.
Следующее создает новый экземпляр класса Counter и трижды вызывает
метод increment () перед отображением текущего значения счетчика на экране:
counter = Counter()
counter.increment()
counter.increment()
counter.increment()
print(counter.value())
Результат:
3
Он работает отлично, но имеет одну проблему. Извне класса Counter вы
по-прежнему можете получить доступ к текущему атрибуту и изменить его на
все, что захотите. Например:
counter = Counter()
counter.increment()
counter.increment()
counter.current = -999
print(counter.value())
Результат:
-999
В этом примере мы создаем экземпляр класса Counter, дважды вызываем
метод increment() и устанавливаем для текущего атрибута недопустимое
значение -999.
Так как же предотвратить изменение текущего атрибута вне класса
Counter?
Вот почему в игру вступают частные атрибуты.
1.1. Частные атрибуты
Частные атрибуты могут быть доступны только из методов класса.
Другими словами, они не могут быть доступны извне класса.
В Python нет концепции частных атрибутов. Другими словами, все
атрибуты доступны извне класса.
По соглашению, вы можете определить частный атрибут, поставив
перед ним один знак подчеркивания (_):
_attribute
Это означает, что _attribute не должен изменяться и может претерпеть
критические изменения в будущем.
Следующее переопределяет класс Counter с текущим как частный
атрибут по соглашению:
class Counter:
def __init__(self):
self._current = 0
def increment(self):
self._current += 1
def value(self):
return self._current
def reset(self):
self._current = 0
1.2. Изменение имени с двойным подчеркиванием
Если вы поставите перед именем атрибута двойное подчеркивание (__),
например:
__attribute
Python автоматически изменит имя __attribute на:
_class__attribute
В Python это называется искажением имени. Поступая так, вы не можете
получить доступ к __attribute непосредственно извне класса, например:
instance.__attribute
Однако вы все равно можете получить к нему доступ, используя имя
_class__attribute:
instance._class__attribute
В следующем примере переопределяется класс Counter с атрибутом
__current:
class Counter:
def __init__(self):
self.__current = 0
def increment(self):
self.__current += 1
def value(self):
return self.__current
def reset(self):
self.__current = 0
Теперь, если вы попытаетесь получить доступ к атрибуту __current, вы
получите сообщение об ошибке:
counter = Counter()
print(counter.__current)
Результат:
AttributeError: 'Counter' object has no attribute '__current'
Однако вы можете получить доступ к атрибуту __current как
_Counter___current следующим образом:
counter = Counter()
print(counter._Counter__current)
 Инкапсуляция - это упаковка данных и методов в класс, чтобы вы
могли скрыть информацию и ограничить доступ извне.
 Префикс атрибута с одним подчеркиванием (_), чтобы сделать его
закрытым по соглашению.
 Префикс атрибута с двойным подчеркиванием (__), чтобы
использовать изменение имени.
2. Наследование
Наследование - мощная функция объектно-ориентированного
программирования.
Это относится к определению нового класса с небольшими изменениями
существующего класса или без них. Новый класс называется производным
(или дочерним) классом, а тот, от которого он наследуется, называется
базовым (или родительским) классом.
Наследование позволяет нам определить класс, который берет всю
функциональность от родительского класса и позволяет нам добавлять
больше. В этом руководстве вы научитесь использовать наследование в
Python.
2.1. Синтаксис наследования Python
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
Производный класс наследует функции от базового класса, и к нему
могут быть добавлены новые функции. Это приводит к повторному
использованию кода.
Чтобы продемонстрировать использование наследования, давайте
рассмотрим пример. Многоугольник - это замкнутая фигура с 3 или более
сторонами. Скажем, у нас есть класс под названием Polygon, определенный
следующим образом.
class Polygon:
def __init__(self, no_of_sides):
self.n = no_of_sides
self.sides = [0 for i in range(no_of_sides)]
def inputSides(self):
self.sides = [float(input("Enter side "+str(i+1)+" : ")) for i in range(self.n)]
def dispSides(self):
for i in range(self.n):
print("Side",i+1,"is",self.sides[i])
Этот класс имеет атрибуты данных для хранения количества сторон n и
величины каждой стороны в виде списка, называемого сторонами. Метод
inputSides() принимает величину каждой стороны, а dispSides() отображает эти
длины сторон.
Треугольник - это многоугольник с 3 сторонами. Итак, мы можем
создать класс Triangle, который наследуется от Polygon. Это делает все
атрибуты класса Polygon доступными для класса Triangle.
Нам не нужно определять их снова (возможность повторного
использования кода). Треугольник можно определить следующим образом.
class Triangle(Polygon):
def __init__(self):
Polygon.__init__(self,3)
def findArea(self):
a, b, c = self.sides
# calculate the semi-perimeter
s = (a + b + c) / 2
area = (s*(s-a)*(s-b)*(s-c)) ** 0.5
print('The area of the triangle is %0.2f' %area)
Однако класс Triangle имеет новый метод findArea() для поиска и печати
площади треугольника. Вот пример выполнения.
>>> t = Triangle()
>>> t.inputSides()
Enter side 1 : 3
Enter side 2 : 5
Enter side 3 : 4
>>> t.dispSides()
Side 1 is 3.0
Side 2 is 5.0
Side 3 is 4.0
>>> t.findArea()
The area of the triangle is 6.00
Мы видим, что, хотя мы не определили такие методы, как inputSides()
или dispSides() отдельно для класса Triangle, мы смогли их использовать. Если
атрибут не найден в самом классе, поиск продолжается до базового класса. Это
повторяется рекурсивно, если базовый класс сам является производным от
других классов.
2.2. Переопределение метода в Python
В приведенном выше примере обратите внимание, что метод __init __ ()
был определен в обоих классах, Triangle и Polygon. Когда это происходит,
метод в производном классе переопределяет метод в базовом классе. Это
означает, что __init __ () в Triangle получает предпочтение перед __init__ в
Polygon.
Обычно при переопределении базового метода мы стремимся
расширить определение, а не просто заменить его. То же самое делается путем
вызова метода в базовом классе из метода в производном классе (вызов
Polygon .__ init __ () из __init __ () в Triangle).
Лучшим вариантом было бы использование встроенной функции
super(). Итак, super() .__ init __ (3) эквивалентен Polygon. __ init __ (self, 3) и
является предпочтительным. Чтобы узнать больше о функции super() в Python,
посетите функцию Python super ().
Две встроенные функции isinstance() и issubclass() используются для
проверки наследования.
Функция isinstance() возвращает True, если объект является экземпляром
класса или других классов, производных от него. Каждый класс в Python
наследуется от объекта базового класса.
>>> isinstance(t,Triangle)
True
>>> isinstance(t,Polygon)
True
>>> isinstance(t,int)
False
>>> isinstance(t,object)
True
Similarly, issubclass() is used to check for class inheritance.
>>> issubclass(Polygon,Triangle)
False
>>> issubclass(Triangle,Polygon)
True
>>> issubclass(bool,int)
True
3. Полиморфизм
Буквальное значение полиморфизма - это условие возникновения в
разных формах.
Полиморфизм - очень важное понятие в программировании. Это
относится к использованию сущности одного типа (метода, оператора или
объекта) для представления разных типов в разных сценариях.
Мы знаем, что оператор + широко используется в программах на Python.
Но у него нет одноразового использования. Для целочисленных типов данных
оператор + используется для выполнения арифметической операции
сложения.
num1 = 1
num2 = 2
print(num1+num2)
Следовательно, вышеуказанная программа выводит 3.
Точно так же для строковых типов данных оператор + используется для
выполнения конкатенации.
str1 = "Python"
str2 = "Programming"
print(str1+" "+str2)
В результате вышеприведенная программа выводит Python
Programming.
Здесь мы видим, что один оператор + использовался для выполнения
различных операций с разными типами данных. Это один из самых простых
случаев полиморфизма в Python.
3.1. Полиморфизм функций в Python
В Python есть некоторые функции, которые могут работать с
несколькими типами данных. Одной из таких функций является функция len().
Он может работать со многими типами данных в Python. Посмотрим на
несколько примеров использования функции.
print(len("Programiz"))
print(len(["Python", "Java", "C"]))
print(len({"Name": "John", "Address": "Nepal"}))
Результат
9
3
2
Здесь мы видим, что многие типы данных, такие как строка, список,
кортеж, набор и словарь, могут работать с функцией len(). Однако мы видим,
что он возвращает конкретную информацию о конкретных типах данных.
Полиморфизм в функции len() в Python
3.2. Полиморфизм классов в Python
Мы можем использовать концепцию полиморфизма при создании
методов класса, поскольку Python позволяет разным классам иметь методы с
одинаковыми именами.
Позже мы можем обобщить вызов этих методов, не обращая внимания
на объект, с которым мы работаем. Давайте посмотрим на пример:
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a cat. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Meow")
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(f"I am a dog. My name is {self.name}. I am {self.age} years old.")
def make_sound(self):
print("Bark")
cat1 = Cat("Kitty", 2.5)
dog1 = Dog("Fluffy", 4)
for animal in (cat1, dog1):
animal.make_sound()
animal.info()
animal.make_sound()
Результат
Meow
I am a cat. My name is Kitty. I am 2.5 years old.
Meow
Bark
I am a dog. My name is Fluffy. I am 4 years old.
Bark
Здесь мы создали два класса Cat и Dog. Они имеют схожую структуру и
одинаковые имена методов info () и make_sound ().
Однако обратите внимание, что мы не создали общий суперкласс и не
связали классы вместе каким-либо образом. Даже в этом случае мы можем
упаковать эти два разных объекта в кортеж и перебирать его, используя общую
переменную животного. Возможно за счет полиморфизма.
Download