Главная страница
Навигация по странице:

  • Вывод: python simplestclass.py Как это работает

  • Объекты (экземпляры классов)

  • Полем

  • Как это работает

  • Python Основы OOP Œ 1. Объектноориентированное программирование на Python


    Скачать 300.03 Kb.
    НазваниеОбъектноориентированное программирование на Python
    АнкорPython Основы OOP Œ 1
    Дата03.02.2023
    Размер300.03 Kb.
    Формат файлаdocx
    Имя файлаPython Основы OOP Œ 1.docx
    ТипДокументы
    #919166

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

    Введение


    Объектно-ориентированное программирование (ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов.
    Класс — тип, описывающий устройство объектов.

    Объект — это экземпляр класса.
    Класс можно сравнить с чертежом, по которому создаются объекты.
    Объектно-ориентированная парадигма имеет несколько принципов:

    • Данные структурируются в виде объектов, каждый из которых имеет определенный тип, то есть принадлежит к какому-либо классу.

    • Классы – результат формализации решаемой задачи, выделения главных ее аспектов.

    • Внутри объекта инкапсулируется логика работы с относящейся к нему информацией.

    • Объекты в программе взаимодействуют друг с другом, обмениваются запросами и ответами.

    • При этом объекты одного типа сходным образом отвечают на одни и те же запросы.

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



    Python соответствует принципам объектно-ориентированного программирования. В python ВСЁ является объектами - и строки, и списки, и словари, и даже функции.

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

    Основы ООП


    Класс (class) - элемент программы, который описывает какой-то тип данных. Класс описывает шаблон для создания объектов, как правило, указывает переменные этого объекта и действия, которые можно выполнять применимо к объекту.

    Экземпляр класса (instance) - объект, который является представителем класса.

    Метод (method) - функция, которая определена внутри класса и описывает какое-то действие, которое поддерживает класс

    Переменная экземпляра (instance variable, а иногда и instance attribute) - данные, которые относятся к объекту

    Переменная класса (class variable) - данные, которые относятся к классу и разделяются всеми экземплярами класса

    Атрибут экземпляра (instance attribute) - переменные и методы, которые относятся к объектам (экземплярам) созданным на основании класса. У каждого объекта есть своя копия атрибутов.
    Пример из реальной жизни в стиле ООП:

    • Проект дома - это класс

    • Конкретный дом, который был построен по проекту - экземпляр класса

    • Такие особенности как цвет дома, количество окон - переменные экземпляра, то есть конкретного дома

    • Дом можно продать, покрасить, отремонтировать - это методы



    Основы ООП в Python

    Классы



    Примечание: Имена классов: в Python принято писать имена классов в формате CamelCase.
    Создадим свой пустой класс (объявление класса):

    class Person:
    def sayHi(self):
    print('Привет! Как дела?')

    p = Person()
    p.sayHi()

    Вывод:

    python simplestclass.py

    <__main__.Person object at 0x019F85F0>

    Как это работает:

    Мы создаём новый класс при помощи оператора class и имени класса. За этим следует блок выражений, формирующих тело класса. В данном случае блок у нас пуст, на что указывает оператор pass.

    Далее мы создаём объект-экземпляр класса, записывая имя класса со скобками. (Мы узнаем больше о реализации в следующем разделе). Для проверки мы выясняем тип переменной, просто выводя её на экран. Так мы видим, что у нас есть экземпляр класса Person в модуле __main__.

    Обратите внимание, что выводится также и адрес в памяти компьютера, где хранится ваш объект. На вашем компьютере адрес будет другим, так как Python хранит объекты там, где имеется свободное место.
    Классы можно наследовать от других классов. Классы-родители (супер-классы) перечисляются в скобках через запятую (реализацию наследования подробнее рассмотрим ниже):

    class SomeClass(ParentClass1, ParentClass2, ...):
    # поля и методы класса SomeClass


    Свойства классов устанавливаются с помощью простого присваивания:

    class SomeClass():
    attr1 = 42
    attr2 = "Hello, World"


    Методы объявляются как простые функции внутри класса:

    class SomeClass():
    def method1(self, x):
    # код метода

    Обратите внимание на первый аргумент – self – общепринятое имя для ссылки на объект, в контексте которого вызывается метод. self - обязательный аргумент, содержащий в себе экземпляр класса, передающийся при вызове метода поэтому этот аргумент должен присутствовать во всех методах класса.

    self



    Методы класса имеют одно отличие от обычных функций: они должны иметь дополнительно имя, добавляемое к началу списка параметров. Однако, при вызове метода никакого значения этому параметру присваивать не нужно – его укажет Python. Эта переменная указывает на сам объект экземпляра класса, и по традиции она называется self.

    Хотя этому параметру можно дать любое имя, настоятельно рекомендуется использовать только имя self; использование любого другого имени не приветствуется. Есть много достоинств использования стандартного имени: во-первых, любой человек, просматривающий вашу программу, легко узнает его; во-вторых, некоторые специализированные Интегрированные среды разработки (IDE) изначально рассчитаны на использование self.
    Примечание:

    Замечание для программистов на C++, Java и C# self в Python эквивалентно указателю this в C++ и ссылке this в Java и C#.
    Поясним работу self на примере: Предположим, у нас есть класс с именем MyClass и экземпляр этого класса с именем myobject. При вызове метода этого объекта, например, myobject.method(arg1, arg2), Python автоматически превращает это MyClass.method(myobject, arg1, arg2) – в этом и состоит смысл self. Это также означает, что если какой-либо метод не принимает аргументов, у него всё равно будет один аргумент – self.

    Дополнительный материал по self:

    • https://pythonz.net/references/named/self/



    Объекты (экземпляры классов)



    Создадим несколько экземпляров класса, который мы объявили выше:
    Пример 1:

    class SomeClass(object):
    attr1 = 42

    def method1(self, x):
    return 2*x

    obj1 = SomeClass()
    obj1.method1(6) # 12
    obj1.attr1 # 42
    obj2 = SomeClass()

    obj2.method1(8) # 16

    obj2.attr1 # 42


    Пример 2:

    class Person:
    name = "Tom"

    def display_info(self):
    print("Привет, меня зовут", self.name)

    person1 = Person()
    person1.display_info() # Привет, меня зовут Tom

    person2 = Person()
    person2.name = "Sam"
    person2.display_info() # Привет, меня зовут Sam


    Класс Person определяет атрибут name, который хранит имя человека, и метод display_info, с помощью которого выводится информация о человеке.

    После определения класс Person создаем пару его объектов - person1 и person2. Используя имя объекта, мы можем обратиться к его методам и атрибутам. В данном случае у каждого из объектов вызываем метод display_info(), который выводит строку на консоль, и у второго объекта также изменяем атрибут name. При этом при вызове метода display_info не надо передавать значение для параметра self.

    Конструктор (__init__)


    В ООП конструктором класса называют метод, который автоматически вызывается при создании объектов. Его также можно назвать конструктором объектов класса. Имя такого метода обычно регламентируется синтаксисом конкретного языка программирования. Так в Java имя конструктора класса совпадает с именем самого класса. В Python же роль конструктора играет метод __init__().

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

    При этом методы перегрузки операторов не надо вызывать по имени. Вызовом для них является сам факт участия объекта в определенной операции. В случае конструктора класса – это операция создания объекта. Так как объект создается в момент вызова класса по имени, то в этот момент вызывается метод __init__(), если он определен в классе.

    Необходимость конструкторов связана с тем, что нередко объекты должны иметь собственные свойства сразу. Пусть имеется класс Person, объекты которого обязательно должны иметь имя и фамилию. Если класс будет описан подобным образом.
    Для примера возьмем класс Point (точка 3d пространства), объекты которого должны иметь определенные координаты:

    class Point(object):
    def __init__(self, x, y, z):
    self.coord = (x, y, z)

    p1 = Point(13, 14, 15)
    p2 = Point(23, 24, 25)

    p1.coord # (13, 14, 15)

    p2.coord # (23, 24, 25)


    Рассмотрим еще один пример, создадим класс Person:

    class Person:
    def __init__(self, n, s):
    self.name = n
    self.surname = s

    p1 = Person("Sam", "Baker")
    print(p1.name, p1.surname)


    Здесь при вызове класса в круглых скобках передаются значения, которые будут присвоены параметрам метода __init__().
    Однако бывает, что надо допустить создание объекта, даже если никакие данные в конструктор не передаются. В таком случае параметрам конструктора класса задаются значения по умолчанию:

    class Rectangle:
    def __init__(self, w = 0.5, h = 1):
    self.width = w
    self.height = h
    def square(self):
    return self.width * self.height

    rec1 = Rectangle(5, 2)
    rec2 = Rectangle()
    rec3 = Rectangle(3)
    rec4 = Rectangle(h = 4)
    print(rec1.square())
    print(rec2.square())
    print(rec3.square())
    print(rec4.square())

    #Вывод

    10

    0.5

    3

    2.0

    Деструктор (__del__)


    Если конструктор вызывается при создании объекта, то перед уничтожением объекта автоматически вызывается метод, называемый деструктором т.е. "уничтожитель". В языке программирования Python деструктор реализуется в виде предопределенного метода __del__(). Следует заметить, что метод не будет вызван, если на экземпляр класса существует хотя бы одна ссылка. Кроме того, т.к. интерпретатор самостоятельно заботится об удалении объектов (инструмент garbage collector), использование деструктора в языке программирования Python не имеет особого смысла.


    class Class1:
    def __init__(self): # Конструктор класса
    print("Вызван метод __init__()")
    def __del__(self): # Деструктор класса
    print("Вызван метод __del__()")
    c1 = Class1() # Выведет: Вызван метод __init__()
    del c1 # Выведет: Вызван метод __del__()
    c2 = Class1() # Выведет: Вызван метод __init__()
    c3 = c2 # Создаем ссылку на экземпляр класса
    del c2 # Ничего не выведет, т.к. существует ссылка
    del c3 # Выведет: Вызван метод __del__()



    Практическая работа. Конструктор и деструктор


    Напишите программу по следующему описанию:

    1. Есть класс Person, конструктор которого принимает три параметра (не учитывая self) – имя, фамилию и квалификацию специалиста. Квалификация имеет значение заданное по умолчанию, равное единице.

    2. У класса Person есть метод, который возвращает строку, включающую в себя всю информацию о сотруднике.

    3. Класс Person содержит деструктор, который выводит на экран фразу "До свидания, мистер …" (вместо троеточия должны выводиться имя и фамилия объекта).

    4. В основной ветке программы создайте три объекта класса Person. Посмотрите информацию о сотрудниках и увольте самое слабое звено.

    5. В конце программы добавьте функцию input(), чтобы скрипт не завершился сам, пока не будет нажат Enter. Иначе вы сразу увидите как удаляются все объекты при завершении работы программы.



    Параметры и методы классов


    С точки зрения пространства имен класс можно представить подобным модулю. Также как в модуле в классе могут быть свои переменные со значениями и функции. Также как в модуле у класса есть собственное пространство имен, доступ к которому возможен через имя класса:
    class B:
    n = 5
    def adder(v):
    return v + B.n

    >>> B.n
    5
    >>> B.adder(4)
    9
    Примечание: В данном примере поле n и метод adder являются полем и методом класса и ключевое слово self не используется, т.к. обращение к полям и методам происходит на уровне всего класса, а не отдельных объектов.. Отличие атрибутов и методов класса от атрибутов и методов объектов будет рассмотрено ниже.
    В случае классов используется особая терминология. Пусть имена, определенные в классе, называются атрибутами этого класса. В примере имена n и adder – это атрибуты класса B. Атрибуты-переменные часто называют полями или свойствами (в других языках понятия "поле" и "свойство" не совсем одно и то же). Полем является n. Атрибуты-функции называются методами. Методом в классе B является adder. Количество свойств и методов в классе может быть любым.

    Переменные класса и объекта


    Данные, т.е. поля, являются не чем иным, как обычными переменными, заключёнными в пространствах имён классов и объектов. Это означает, что их имена действительны только в контексте этих классов или объектов. Отсюда и название “пространство имён”.

    Существует два типа полей: переменные класса (рассмотрели выше) и переменные объекта, которые различаются в зависимости от того, принадлежит ли переменная классу или объекту соответственно.
    Переменные класса разделяемы – доступ к ним могут получать все экземпляры этого класса. Переменная класса существует только одна, поэтому когда любой из объектов изменяет переменную класса, это изменение отразится и во всех остальных экземплярах того же класса.
    Переменные объекта принадлежат каждому отдельному экземпляру класса. В этом случае у каждого объекта есть своя собственная копия поля, т.е. не разделяемая и никоим образом не связанная с другими такими же полями в других экземплярах. Это легко понять на примере (сохраните как objvar.py):


    class Robot:
    '''Представляет робота с именем.'''
    # Переменная класса, содержащая количество роботов
    population = 0

    def __init__(self, name):
    '''Инициализация данных.'''
    self.name = name
    print('(Инициализация {0})'.format(self.name))

    # При создании этой личности, робот добавляется
    # к переменной 'population'
    Robot.population += 1

    def __del__(self):
    '''Я умираю.'''
    print('{0} уничтожается!'.format(self.name))

    Robot.population -= 1

    if Robot.population == 0:
    print('{0} был последним.'.format(self.name))
    else:
    print('Осталось {0:d} работающих роботов.'.format(Robot.population))

    def sayHi(self):
    '''Приветствие робота.

    Да, они это могут.'''
    print('Приветствую! Мои хозяева называют меня {0}.'.format(self.name))

    def howMany():
    '''Выводит численность роботов.'''
    print('У нас {0:d} роботов.'.format(Robot.population))

    howMany = staticmethod(howMany)

    droid1 = Robot('R2-D2')
    droid1.sayHi()
    Robot.howMany()

    droid2 = Robot('C-3PO')
    droid2.sayHi()
    Robot.howMany()

    print("\nЗдесь роботы могут проделать какую-то работу.\n")

    print("Роботы закончили свою работу. Давайте уничтожим их.")
    del droid1
    del droid2

    Robot.howMany()


    Вывод:

    $ python3 objvar.py

    (Инициализация R2-D2)

    Приветствую! Мои хозяева называют меня R2-D2.

    У нас 1 роботов.

    (Инициализация C-3PO)

    Приветствую! Мои хозяева называют меня C-3PO.

    У нас 2 роботов.
    Здесь роботы могут проделать какую-то работу.
    Роботы закончили свою работу. Давайте уничтожим их.

    R2-D2 уничтожается!

    Осталось 1 работающих роботов.

    C-3PO уничтожается!

    C-3PO был последним.

    У нас 0 роботов.
    Как это работает:

    Это длинный пример, но он помогает продемонстрировать природу переменных класса и объекта. Здесь population принадлежит классу Robot, и поэтому является переменной класса. Переменная name принадлежит объекту (ей присваивается значение при помощи self), и поэтому является переменной объекта.

    Таким образом, мы обращаемся к переменной класса population как Robot.population, а не self.population. К переменной же объекта name во всех методах этого объекта мы обращаемся при помощи обозначения self.name. Помните об этой простой разнице между переменными класса и объекта. Также имейте в виду, что переменная объекта с тем же именем, что и переменная класса, сделает недоступной (“спрячет”) переменную класса!

    Метод howMany принадлежит классу, а не объекту.
    Примечание:

    В этом примере мы также наблюдали применение строк документации для классов, равно как и для методов. Во время выполнения мы можем обращаться к строке документации класса при помощи Robot.__doc__, а к строке документации метода – при помощи Robot.sayHi.__doc__.

    Динамическое изменение (не рекомендуется использовать)



    Классы в Python могут динамически изменяться после определения:

    class SomeClass(object):
    # пустой класс
    pass

    a = SomeClass()
    b = SomeClass()
    a.arg = 1 # у экземпляра a появился атрибут arg, равный 1
    b.arg = 2 # а у экземпляра b - атрибут arg, равный 2
    print(a.arg)
    print(b.arg)
    c = A()
    print(c.arg) # а у этого экземпляра нет arg


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

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

    Практическая работа “Игра воин”:


    Напишите программу по следующему описанию. Есть класс "Воин". От него создаются два экземпляра-юнита. Каждому устанавливается здоровье в 100 очков. В случайном порядке они бьют друг друга. Тот, кто бьет, здоровья не теряет. У того, кого бьют, оно уменьшается на 20 очков от одного удара. После каждого удара надо выводить сообщение, какой юнит атаковал, и сколько у противника осталось здоровья. Как только у кого-то заканчивается ресурс здоровья, программа завершается сообщением о том, кто одержал победу.


    написать администратору сайта