Объектно-ориентированное программирование на python

Классы

Класс – это прототип объекта.

В коде классы определяются ключевым словом class.

Создайте файл shark.py. Попробуйте определить класс Shark с двумя функциями:

Определяемые в классе функции называются методами.

В данном случае в качестве аргумента используется слово self – оно ссылается на объекты, основанные на этом классе. Для этого параметр self должен всегда быть первым в функции (но не обязательно единственным её параметром).

Новый класс Shark пока что не создал ни одного объекта Shark. То есть, если вы запустите программу shark.py, ничего не произойдёт.

Теперь у вас есть шаблон для создания объектов.

How to Check an Object’s Class

You can check an object’s class with the attribute. Generally, you’ll get the same result when using the function.

Here’s how to output the class of an object (using both syntaxes):

a = «Hello World»

print(type(a))
print(a.__class__)Result

<class 'str'>
<class 'str'>

What that tells us is that the string is based on the class.

You can do the same thing for any object. Here are some more examples:

from myPackage.calculations import multiplyMe

print(type(10))
print(type(1.0))
print(type())
print(type((1,2,3)))
print(type({1,2,3}))
print(type({1:»Hello», 2:»World»}))
print(type(multiplyMe))
print(type(max))Result

<class 'int'>
<class 'float'>
<class 'list'>
<class 'tuple'>
<class 'set'>
<class 'dict'>
<class 'function'>
<class 'builtin_function_or_method'>
  • Python Modules
  • Read/Write Files

Класс

Классы, в некотором смысле, подобны чертежам: это не объекты сами по себе, а их схемы. Класс «банковских счетов» имеет строго определенные и одинаковые для всех атрибуты, но объекты в нём — сами счета — уникальны.

Как в Python создать класс

В Python классы и объекты по смыслу не отличаются от других языков. Нюансы в реализации. Для создания класса в Питоне необходимо написать инструкцию , а затем выбрать имя. В простейшем случае, класс выглядит так:

Для именования классов в Python обычно используют стиль «camel case», где первая буква — заглавная.

Конструктор

Метод, который вызывается при создании объектов, в ООП зовётся конструктором. Он нужен для объектов, которые изначально должны иметь какие-то значение. Например, пустые экземпляры класса «Студент» бессмысленны, и желательно иметь хотя бы минимальный обозначенный набор вроде имени, фамилии и группы.

В качестве Питоновского конструктора выступает метод

Атрибуты класса

Вы уже поняли, что у каждого класса есть собственный набор характеристик, который помогает описывать его сущность. Эти свойства еще называются полями или атрибутами.

Поля могут быть статическими и динамическими:

  • Статические поля (поля класса) можно использовать без создания объекта. А значит, конструктор вам не нужен.
  • Динамические поля (поля объекта) задаются с помощью конструктора, и тут уже, как вы видели, экземпляр нужно создать, а полям присвоить значения.

️ Обратите внимание — статический и динамический атрибут может иметь одно и то же имя:

Методы класса

Метод — это функция класса.

Например, у всех научно-фантастических космических кораблей есть бортовое оружие. И оно может стрелять.

Что такое self?

Аналог этого ключевого слова в других языках — слово . — это всего лишь ссылка на текущий экземпляр класса.

Отличный пример с котофеями:

  1. Все котики умеют мурлыкать;
  2. Эта способность реализована в классе , как метод ;
  3. Вы хотите, чтобы ваш кот по имени Пушок помурчал;
  4. Если сделать так: , то мурлыкать начнут все коты во Вселенной;
  5. Но так как вам нужен один конкретный кот, то нужно вызвать метод иначе: ;
  6. Сделано. Пушок мурлыкает.

Уровни доступа атрибутов и методов

В Питоне не существует квалификаторов доступа к полям класса. Отсутствие аналогов связки public/private/protected можно рассматривать как упущение со стороны принципа инкапсуляции.

Декораторы

Декоратор — это функция-обёртка. В неё можно завернуть другой метод, и, тем самым, изменить его функциональность, не меняя код.

Принципы ООП

Объектно-ориентированный язык работает по следующим принципам:

  • Все данные представляются объектами
  • Программа является набором взаимодействующих объектов, посылающих друг другу сообщения
  • Каждый объект имеет собственную часть памяти и может иметь в составе другие объекты
  • Каждый объект имеет тип
  • Объекты одного типа могут принимать одни и те же сообщения (и выполнять одни и те же действия)

Идеи/принципы объектно-ориентированного программирования:

  1. Наследование. Возможность выделять общие свойства и методы классов в один класс верхнего уровня (родительский). Классы, имеющие общего родителя, различаются между собой за счет включения в них различных дополнительных свойств и методов.
  2. Инкапсуляция. Свойства и методы класса делятся на доступные из вне (опубликованные) и недоступные (защищенные). Защищенные атрибуты нельзя изменить, находясь вне класса. Опубликованные же атрибуты также называют интерфейсом объекта, т. к. с их помощью с объектом можно взаимодействовать. По идеи, инкапсуляция призвана обеспечить надежность программы, т.к. изменить существенные для существования объекта атрибуты становится невозможно.
  3. Полиморфизм. Полиморфизм подразумевает замещение атрибутов, описанных ранее в других классах: имя атрибута остается прежним, а реализация уже другой. Полиморфизм позволяет специализировать (адаптировать) классы, оставляя при этом единый интерфейс взаимодействия.

Преимущества ООП

В связи со своими особенностями объектно-ориентированное программирование имеет ряд преимуществ перед структурным (и др.) программированием. Выделим некоторые из них:

  1. Использование одного и того же программного кода с разными данными. Классы позволяют создавать множество объектов, каждый из которых имеет собственные значения атрибутов. Нет потребности вводить множество переменных, т.к объекты получают в свое распоряжение индивидуальные так называемые пространства имен. Пространство имен конкретного объекта формируется на основе класса, от которого он был создан, а также от всех родительских классов данного класса. Объект можно представить как некую упаковку данных.
  2. Наследование и полиморфизм позволяют не писать новый код, а настраивать уже существующий, за счет добавления и переопределения атрибутов. Это ведет к сокращению объема исходного кода.

Особенность ООП

ООП позволяет сократить время на написание исходного кода, однако ООП всегда предполагает большую роль предварительного анализа предметной области, предварительного проектирования. От правильности решений на этом предварительном этапе зависит куда больше,чем от непосредственного написания исходного кода.

Особенности ООП в Python

По сравнению с другими распространенными языками программирования у Python можно выделить следующие особенности, связанные с объектно-ориентированным программированием:

  1. Любое данное (значение) — это объект. Число, строка, список, массив и др. — все является объектом. Бываю объекты встроенных классов (как те,что перечисленные в предыдущем предложении), а бывают объекты пользовательских классов (тех, что создает программист). Для единого механизма взаимодействия предусмотрены методы перегрузки операторов.
  2. Класс — это тоже объект с собственным пространством имен. Это нигде не было указано в данном цикле уроков. Однако это так. Поэтому правильнее было употреблять вместо слова «объект», слово «экземпляр». И говорить «экземпляр объекта», подразумевая под этим созданный на основе класса именно объект, и «экземпляр класса», имея ввиду сам класс как объект.
  3. Инкапсуляции в Python не уделяется особого внимания. В других языках программирования обычно нельзя получить напрямую доступ к свойству, описанному в классе. Для его изменения может быть предусмотрен специальный метод. В Python же это легко сделать, просто обратившись к свойству класса из вне. Несмотря на это в Python все-таки предусмотрены специальные способы ограничения доступа к переменным в классе.

Переопределение метода

Мы можем предоставить некоторую конкретную реализацию метода родительского класса в нашем дочернем классе. Когда метод родительского класса определен в дочернем классе с некоторой конкретной реализацией, эта концепция называется переопределением метода. Нам может потребоваться выполнить переопределение метода в сценарии, когда в дочернем классе требуется другое определение метода родительского класса.

Рассмотрим следующий пример, чтобы выполнить переопределение метода в Python.

 
class Animal: 
    def speak(self): 
        print("speaking") 
class Dog(Animal): 
    def speak(self): 
        print("Barking") 
d = Dog() 
d.speak() 

Выход:

Barking 

Реальный пример переопределения метода –

 
class Bank: 
 def getroi(self): 
 return 10; 
class SBI(Bank): 
    def getroi(self): 
        return 7; 
 
class ICICI(Bank): 
    def getroi(self): 
        return 8; 
b1 = Bank() 
b2 = SBI() 
b3 = ICICI() 
print("Bank Rate of interest:",b1.getroi()); 
print("SBI Rate of interest:",b2.getroi()); 
print("ICICI Rate of interest:",b3.getroi()); 

Выход:

Bank Rate of interest: 10 
SBI Rate of interest: 7 
ICICI Rate of interest: 8 

Документирование классов

Весь код нужно комментировать и документировать. Классы — не исключение. Стоит помнить, что код вы пишите не для себя, и вполне вероятно, что написанное вами придётся поддерживать другим людям. Комментарии повышают читаемость и увеличивают легкость восприятие кода в разы, тем самым экономя время и деньги.

Подробнее о Python-документации:

Документирование кода в Python

ООП ещё долгое время будет оставаться передовой парадигмой программирования. Но учить её полезно и по другой причине. Прямая связь объектно-ориентированного программирования с реальным миром помогает глубже понимать устройство и принципы работы, как самого языка, так и написания кода в целом.

Инкапсуляция в Python

Это концепция упаковки данных так, что внешний мир имеет доступ только к открытым свойствам. Некоторые свойства могут быть скрыты, чтобы уменьшить уязвимость. Это так называемая реализация сокрытия данных. Например, вы хотите купить брюки с интернет-сайта. Данные, которые вам нужны, это их стоимость и доступность. Количество предметов и их расположение — это информация, которая вас не беспокоит. Следовательно, эта информация скрыта.

В Python это реализуется путем создания private, protected и public переменных и методов экземпляра.

Private свойства имеют двойное подчеркивание (__) в начале, в то время как protected имеют одиночное подчеркивание (_). По умолчанию, все остальные переменные и методы являются public.

Private атрибуты доступны только внутри класса и недоступны для дочернего класса (если он унаследован). Protected доступны внутри класса, но доступны и дочернему классу. Все эти ограничения сняты для public атрибутов.

Следующие фрагменты кода являются примером этой концепции:

2.2. Перебор всех ключей в словаре методом keys().

Метод keys() удобен если вы собираетесь работать с ключами в словаре. Переберем словарь и выведем все ключи в нем:

>>> year = {‘январь’: 31, ‘февраль’: 28, ‘март’: 31, ‘апрель’: 30}
>>> for key in year.keys():
…     print(key)
…январь
февраль
март
апрель

В Python перебор ключей используется по умолчанию при переборе словаря. Две записи ниже дают один и тот же результат.

>>> for key in year.keys():

>>> for key in year:

Явный вызов метода keys() может упростить чтение вашего кода. 

Начиная с Python 3.7 перебор содержимого словаря возвращает элементы в том порядке, в каком они вставлялись. Один из способов перебрать элементы в определенном порядке, вызвать функцию sorted(). 

>>> for key in sorted(year.keys()):
…     print(key)
…апрель
март
февраль
январь

В результате ключи сортируются по алфавиту.

Переменные класса или переменные экземпляра?

Когда переменная определяется на уровне класса, она называется переменной класса. Когда переменная определяется в конструкторе, она называется переменной экземпляра.

Переменные класса являются общими для всех экземпляров класса, тогда как переменные экземпляра уникальны для экземпляра

Итак, очень важно понимать, когда использовать переменную класса, а когда — переменную экземпляра

В предыдущих примерах атрибут employee_id уникален для экземпляра Employee, поэтому лучше иметь его в качестве переменной экземпляра и определять в конструкторе.

Предположим, мы хотим отслеживать количество созданных экземпляров сотрудников и выделенных идентификаторов сотрудников. В этом случае мы можем использовать переменные класса для хранения этих данных и обновления экземплярами.

class Employee:
    count = 0
    ids_list = []

    def __init__(self, i):
        self.id = i
        Employee.count += 1
        self.ids_list.append(i)


for x in range(0, 10):
    emp = Employee(x)

print(f'Number of employees created = {Employee.count}')
print(f'List of employee ids allocated = {Employee.ids_list}')

emp = Employee(1000)
print(f'List of employee ids allocated = {emp.ids_list}')

Выход:

Number of employees created = 10
List of employee ids allocated = 
List of employee ids allocated = 

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

Встроенные функции

print (x, sep = 'y') печатает x объектов, разделенных y
len (x) возвращает длину x (s, L или D)
min (L ) возвращает минимальное значение в L
max (L) возвращает максимальное значение в L
sum (L) возвращает сумму значений в диапазоне L
range(n1,n2,n) (n1, n2, n) возвращает последовательность чисел от n1 до n2 с шагом n
abs (n) возвращает абсолютное значение n
round (n1, n) возвращает число n1, округленное до n цифр
type (x) возвращает тип x (string, float, list, dict…)
str (x) преобразует x в string 
list (x) преобразует x в список
int (x) преобразует x в целое число
float (x) преобразует x в число с плавающей запятой
help (s) печатает справку о x
map (function, L) Применяет функцию к значениям в L

Объекты

Объект – это экземпляр класса. Используйте класс Shark для создания объекта jimmy.

Вы инициализировали объект jimmy как экземпляр класса.

Теперь добавьте методы класса Shark в объект jimmy:

Теперь объект jimmy, созданный на основе класса Shark, использует методы swim() и be_awesome(), которые были вызваны с помощью оператора-точки. Этот оператор позволяет сослаться на атрибут объекта.  В этом случае атрибут является методом, и он вызывается со скобками, как любая обычная функция.

Поскольку ключевое слово self является параметром методов, как определено в классе Shark, объект jimmy передается методам. Параметр self позволяет методам ссылаться на атрибуты объекта.

При вызове методов объект jimmy автоматически передается с помощью оператора-точки.

Добавьте объект в файл shark.py:

Запустите программу:

Многоуровневое наследование

Многоуровневое наследование позволяет производному классу наследовать свойства от непосредственного родительского класса, который, в свою очередь, наследует свойства от своего родительского класса.

Пример:

class employee()://Super class
def __init__(self,name,age,salary):  
self.name = name
self.age = age
self.salary = salary
class childemployee1(employee)://First child class
def __init__(self,name,age,salary):
self.name = name
self.age = age
self.salary = salary

class childemployee2(childemployee1)://Second child class
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
emp1 = employee('harshit',22,1000)
emp2 = childemployee1('arjun',23,2000)

print(emp1.age)
print(emp2.age)

Выход: 22,23.

Объяснение:

  • Это четко объясняется в коде, написанном выше. Здесь я определил суперкласс как сотрудник, а дочерний класс, как childemployee1. Теперь childemployee1 действует, как родитель для childemployee2.
  • Я создал два объекта «emp1» и «emp2», где я передаю параметры «имя», «возраст», «зарплата» для emp1 из суперкласса «сотрудник» и «имя», «возраст», «зарплата» и «идентификатор». Из родительского класса «childemployee1 »

Что такое классы и объекты?

Класс – это набор объектов или план объектов, определяющих общие атрибуты и поведение. Возникает вопрос, как это сделать?

Что ж, он логически группирует данные таким образом, что повторное использование кода становится простым. Я могу привести вам пример из реальной жизни – представьте, что офис становится «сотрудником» как класс и все атрибуты, связанные с ним, такие как «emp_name», «emp_age», «emp_salary», «emp_id» как объекты в Python. Давайте посмотрим с точки зрения кодирования, как создать экземпляр класса и объекта.

Класс определяется ключевым словом «Класс». Пример:

class class1(): // class 1 is the name of the class

Примечание. Python не чувствителен к регистру.

Уничтожение объектов (Сборка мусора)

Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов), чтобы освободить пространство памяти. Процесс, посредством которого Python периодически восстанавливает блоки памяти, которые больше не используются, называется сборкой мусора.

Сборщик мусора в Python запускается во время выполнения программы и запускается, когда счетчик ссылок на объект достигает нуля. Количество ссылок объекта изменяется по мере изменения количества псевдонимов, которые на него указывают.

Счетчик ссылок на объект увеличивается, когда ему присваивается новое имя или он помещается в контейнер (список, кортеж или словарь). Счетчик ссылок объекта уменьшается, когда он удаляется с помощью del , его ссылка переназначается или его ссылка выходит за пределы области видимости. Когда счетчик ссылок объекта достигает нуля, Python собирает его автоматически.

a = 40      # Create object <40>
b = a       # Increase ref. count  of <40> 
c =      # Increase ref. count  of <40> 

del a       # Decrease ref. count  of <40>
b = 100     # Decrease ref. count  of <40> 
c = -1   # Decrease ref. count  of <40>

Обычно вы не замечаете, когда сборщик мусора уничтожает потерянный экземпляр и освобождает его пространство. Но класс может реализовать специальный метод __del __ () , называемый деструктором, который вызывается, когда экземпляр собирается быть уничтоженным. Этот метод может использоваться для очистки любых ресурсов памяти, используемых экземпляром.

Пример

Этот деструктор __del __ () печатает имя класса экземпляра, который должен быть уничтожен

#!/usr/bin/python

class Point:
   def __init__( self, x=0, y=0):
      self.x = x
      self.y = y
   def __del__(self):
      class_name = self.__class__.__name__
      print class_name, "destroyed"

pt1 = Point()
pt2 = pt1
pt3 = pt1
print id(pt1), id(pt2), id(pt3) # prints the ids of the obejcts
del pt1
del pt2
del pt3

Когда приведенный выше код выполняется, он дает следующий результат

3083401324 3083401324 3083401324
Point destroyed

Примечание. В идеале вы должны определять свои классы в отдельном файле, а затем импортировать их в основной файл программы с помощью оператора import .

Ошибки при работе со списками Python

Одна из основных ошибок при работе со списками, это ошибка индексирования. Например, вы пытаетесь вернуть элемент с индексом 5. В результате Python при работе со списком не находит элемент с этим индексом, происходит ошибка индексирования. 

>>> cars =          
>>> cars Traceback (most recent call last):
  File «<stdin>», line 1, in <module>
IndexError: list index out of range

Индекс должен быть целым числом или выражением, дающим целочисленный результат. При попытке использования нецелочисленного индекса происходит ошибка TypeError. Так же ошибка индексирования образуется при попытке обратиться к элементу пустого списка.

Indentation

Use 4 spaces per indentation level.

Continuation lines should align wrapped elements either vertically
using Python’s implicit line joining inside parentheses, brackets and
braces, or using a hanging indent . When using a hanging
indent the following should be considered; there should be no
arguments on the first line and further indentation should be used to
clearly distinguish itself as a continuation line:

# Correct:

# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# Hanging indents should add a level.
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)
# Wrong:

# Arguments on first line forbidden when not using vertical alignment.
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

The 4-space rule is optional for continuation lines.

Optional:

# Hanging indents *may* be indented to other than 4 spaces.
foo = long_function_name(
  var_one, var_two,
  var_three, var_four)

When the conditional part of an if-statement is long enough to require
that it be written across multiple lines, it’s worth noting that the
combination of a two character keyword (i.e. if), plus a single space,
plus an opening parenthesis creates a natural 4-space indent for the
subsequent lines of the multiline conditional. This can produce a visual
conflict with the indented suite of code nested inside the if-statement,
which would also naturally be indented to 4 spaces. This PEP takes no
explicit position on how (or whether) to further visually distinguish such
conditional lines from the nested suite inside the if-statement.
Acceptable options in this situation include, but are not limited to:

# No extra indentation.
if (this_is_one_thing and
    that_is_another_thing):
    do_something()

# Add a comment, which will provide some distinction in editors
# supporting syntax highlighting.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()

(Also see the discussion of whether to break before or after binary
operators below.)

The closing brace/bracket/parenthesis on multiline constructs may
either line up under the first non-whitespace character of the last
line of list, as in:

my_list = 
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or it may be lined up under the first character of the line that
starts the multiline construct, as in:

Переопределяющие методы

Вы всегда можете переопределить ваши родительские методы класса. Одна из причин переопределения родительских методов заключается в том, что вам может потребоваться особая или другая функциональность в вашем подклассе.

Пример

#!/usr/bin/python

class Parent:        # define parent class
   def myMethod(self):
      print 'Calling parent method'

class Child(Parent): # define child class
   def myMethod(self):
      print 'Calling child method'

c = Child()          # instance of child
c.myMethod()         # child calls overridden method

Когда приведенный выше код выполняется, он дает следующий результат

Calling child method

Встроенные атрибуты класса

Каждый класс Python поддерживает следующие встроенные атрибуты, и к ним можно получить доступ, используя оператор точки, как и любой другой атрибут —

  • __dict__ — словарь, содержащий пространство имен класса.
  • __doc__ — Строка документации класса или нет, если она не определена.
  • __name__ — Имя класса.
  • __module__ — Имя модуля, в котором определяется класс. Этот атрибут «__main__» в интерактивном режиме.
  • __bases__ — возможно пустой кортеж, содержащий базовые классы, в порядке их появления в списке базовых классов.

Для приведенного выше класса давайте попробуем получить доступ ко всем этим атрибутам

#!/usr/bin/python

class Employee:
   'Common base class for all employees'
   empCount = 0

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary

print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__

Когда приведенный выше код выполняется, он дает следующий результат

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount':
<function displayCount at 0xb7c84994>, 'empCount': 2, 
'displayEmployee': <function displayEmployee at 0xb7c8441c>, 
'__doc__': 'Common base class for all employees', 
'__init__': <function __init__ at 0xb7c846bc>}

Передача списка функции на Python

При передаче аргумента функции мы можем сразу передать список. В результате функция получает доступ сразу ко всему его содержимому. Воспользуемся функцией square которую писали в , которая выводит квадрат своего аргумента и немного обновим ее. Но в качестве аргумента мы передадим сразу список чисел, которые нужно обработать и возвести в квадрат. 

>>> def square(numbers):
…     «»»Вычисление квадрата числа»»»
…     for number in numbers:
…             print(number ** 2)

>>> numbers =
>>> square(numbers)1
25
36
225
49
2.25

В результате функции square мы передаем список numbers. Для возведения всех чисел в квадрат, вначале нам нужно перебрать данный список с помощью цикла for, а затем каждое число возвести в квадрат. 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector