Как вывести класс в питоне
Класс и объект в Python
Объектно-ориентированное программирование в Python
Python — это процедурно-ориентированный и одновременно объектно-ориентированный язык программирования.
Процедурно-ориентированный
«Процедурно-ориентированный» подразумевает наличие функций. Программист может создавать функции, которые затем используются в сторонних скриптах.
Объектно-ориентированный
«Объектно-ориентированный» подразумевает наличие классов. Есть возможность создавать классы, представляющие собой прототипы для будущих объектов.
Создание класса в Python
Синтаксис для написания нового класса:
Атрибут:
Атрибут — это элемент класса. Например, у прямоугольника таких 2: ширина ( width ) и высота ( height ).
Метод:
Конструктор:
Создание объекта с помощью класса Rectangle:
Что происходит при создании объекта с помощью класса?
При создании объекта класса Rectangle запускается конструктор выбранного класса, и атрибутам нового объекта передаются значения аргументов. Как на этом изображении:
Конструктор с аргументами по умолчанию
В других языках программирования конструкторов может быть несколько. В Python — только один. Но этот язык разрешает задавать значение по умолчанию.
Все требуемые аргументы нужно указывать до аргументов со значениями по умолчанию.
Сравнение объектов
В Python объект, созданный с помощью конструктора, занимает реальное место в памяти. Это значит, что у него есть точный адрес.
Атрибуты
В Python есть два похожих понятия, которые на самом деле отличаются:
Стоит разобрать на практике:
Атрибут
Объекты, созданные одним и тем же классом, будут занимать разные места в памяти, а их атрибуты с «одинаковыми именами» — ссылаться на разные адреса. Например:
Атрибуты функции
Обычно получать доступ к атрибутам объекта можно с помощью оператора «точка» (например, player1.name ). Но Python умеет делать это и с помощью функции.
| Функция | Описание |
|---|---|
| getattr (obj, name[,default]) | Возвращает значение атрибута или значение по умолчанию, если первое не было указано |
| hasattr (obj, name) | Проверяет атрибут объекта — был ли он передан аргументом «name» |
| setattr (obj, name, value) | Задает значение атрибута. Если атрибута не существует, создает его |
| delattr (obj, name) | Удаляет атрибут |
Встроенные атрибуты класса
Объекты класса — дочерние элементы по отношению к атрибутам самого языка Python. Таким образом они заимствуют некоторые атрибуты:
Переменные класса
Переменные класса в Python — это то же самое, что Field в других языках, таких как Java или С#. Получить к ним доступ можно только с помощью имени класса или объекта.
Для получения доступа к переменной класса лучше все-таки использовать имя класса, а не объект. Это поможет не путать «переменную класса» и атрибуты.
У каждой переменной класса есть свой адрес в памяти. И он доступен всем объектам класса.
Составляющие класса или объекта
Примеры работы с классами в Python
Python — объектно-ориентированный язык с начала его существования. Поэтому, создание и использование классов и объектов в Python просто и легко. Эта статья поможет разобраться на примерах в области поддержки объектно-ориентированного программирования Python. Если у вас нет опыта работы с объектно-ориентированным программированием (OOП), ознакомьтесь с вводным курсом или учебным пособием, чтобы понять основные понятия.
Создание классов
Пример создания класса на Python:
Создание экземпляров класса
Доступ к атрибутам
Теперь, систематизируем все.
При выполнении этого кода, мы получаем следующий результат:
Вы можете добавлять, удалять или изменять атрибуты классов и объектов в любой момент.
Вместо использования привычных операторов для доступа к атрибутам вы можете использовать эти функции:
Встроенные атрибуты класса
Для вышеуказанного класса давайте попробуем получить доступ ко всем этим атрибутам:
Когда этот код выполняется, он возвращает такой результат:
Удаление объектов (сбор мусора)
Python автоматически удаляет ненужные объекты (встроенные типы или экземпляры классов), чтобы освободить пространство памяти. С помощью процесса ‘Garbage Collection’ Python периодически восстанавливает блоки памяти, которые больше не используются.
Сборщик мусора Python запускается во время выполнения программы и тогда, когда количество ссылок на объект достигает нуля. С изменением количества обращений к нему, меняется количество ссылок.
Пример работы __del__()
Деструктор __del__() выводит имя класса того экземпляра, который должен быть уничтожен:
Когда вышеуказанный код выполняется и выводит следующее:
Наследование класса в python
Наследование — это процесс, когда один класс наследует атрибуты и методы другого. Класс, чьи свойства и методы наследуются, называют Родителем или Суперклассом. А класс, свойства которого наследуются — класс-потомок или Подкласс.
Вместо того, чтобы начинать с нуля, вы можете создать класс, на основе уже существующего. Укажите родительский класс в круглых скобках после имени нового класса.
Класс наследник наследует атрибуты своего родительского класса. Вы можете использовать эти атрибуты так, как будто они определены в классе наследнике. Он может переопределять элементы данных и методы родителя.
Синтаксис наследования класса
Классы наследники объявляются так, как и родительские классы. Только, список наследуемых классов, указан после имени класса.
Классы в Python
Объектно-ориентированное программирование считается одним из самых эффективных методов создания программ. В объектно-ориентированном программирование создаются классы, описывающие реальные предметы и ситуации, а затем создаете объекты на основе этих описаний. Созданием объекта на основе класса называется созданием экземпляра.
| Содержание страницы: |
|---|
| 1. Создание класса |
| 1.1. Метод __init__() |
| 1.2. Создание экземпляра класса |
| 1.3. Обращение к атрибутам класса |
| 1.4. Вызов методов класса |
| 2. Работа с классами |
| 2.1. Прямое изменение значения атрибута |
| 2.2. Изменение значения атрибута с использованием метода |
| 2.3. Изменение значения атрибута с приращением |
| 3. Наследование класса |
| 3.1. Переопределение методов класса-родителя |
1. Создание класса в Python
Классы в Python могут моделировать практически все что угодно. Создадим простой класс, который будет описывать конкретный автомобиль:
Разберем код по порядку. В начале определяется класс с именем Car ( class Car ). По общепринятым соглашение название класса начинается с символа верхнего регистра. Круглые скобки в определение класса пусты, так как класс создается с нуля. Далее идет строка документации с кратким описанием. ( «»»Описание автомобиля»»» ).
1.1. Метод __init__()
Каждая из двух переменных self.brand = brand и self.model = model снабжена префиксом self и к ним можно обращаться вызовом self.brand и self.model. Значения берутся из параметров brand и model. Переменные, к которым вы обращаетесь через экземпляры, также называются атрибутами.
1.2. Создание экземпляра класса
С помощью класса Car мы можем создавать экземпляры для конкретного автомобиля. Каждый экземпляр описывает конкретный автомобиль и его параметры.
1.3. Обращение к атрибутам класса
К атрибутам экземпляра класса мы можем обращаться через запись:
В записи используется имя экземпляра класса и после точки имя атрибута (car_1.brand) или (car_1.model). В итоге на экран выведется следующая информация:
Bmw
X5
1.4. Вызов методов класса
После создания экземпляра на основе класса Car можете вызывать любые методы, написанные в классе. Чтобы вызвать метод, укажите экземпляр (car_1) и вызываемый метод после точки:
car_1. sold ()
car_1. discount ()
При вызове данных методов, Python выполнит код, написанный в этом методе.
Автомобиль Bmw X5 продан
На автомобиль Bmw X5 скидка 5%
2. Работа с классами на Python
В описание автомобиля есть три атрибута(параметра) это brand, model, years. Также мы создали новый атрибут mileage (пробег) и присвоили ему начальное значение 0. Так как пробег у всех автомобилей разный, в последующем мы сможем изменять этот атрибут. Метод get_full_name будет возвращать полное описание автомобиля. Метод read_mileage будет выводить пробег автомобиля.
Создадим экземпляр с классом Car и запустим методы:
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2. get_full_name() )
car_2. read_mileage()
В результате в начале Python вызывает метот __init__() для создания нового экземпляра. Сохраняет название, модель, год выпуска и создает новый атрибут с пробегом равным 0. В итоге мы получим такой результат:
Автомобиль Audi A4 2019
Пробег автомобиля 0 км.
2.1. Прямое изменение значения атрибута
Для изменения значения атрибута можно обратиться к нему напрямую и присвоить ему новое значение. Изменим пробег автомобиля car_2:
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2.get_full_name())
car_2.mileage = 38
car_2. read_mileage()
Мы обратились к нашему экземпляру car_2 и связанным с ним атрибутом пробега(mileage) и присвоили новое значение 38. Затем вызвали метод read_mileage() для проверки. В результате мы получим следующие данные.
Автомобиль Audi A4 2019
Пробег автомобиля 38 км.
2.2. Изменение значения атрибута с использованием метода
В Python удобнее писать методы, которые будут изменять атрибуты за вас. Для этого вы просто передаете новое значение методу, который обновит значения. Добавим в наш класс Car метод update_mileage() который будет изменять показания пробега.
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2.get_full_name())
car_2. read_mileage()
car_2. update_mileage (17100)
car_2. read_mileage()
Вначале выведем текущие показания пробега ( car_2. read_mileage() ). Затем вызовем метод update_mileage() и передадим ему новое значение пробега ( car_2. update_mileage (17100) ). Этот метод устанавливает пробег 17100. Выведем текущие показания ( car_2. read_mileage() ) и у нас получается:
Автомобиль Audi A4 2019
Пробег автомобиля 0 км.
Пробег автомобиля 17100 км.
2.3. Изменение значения атрибута с приращением
Если вместо того, чтобы присвоить новое значение, требуется изменить с значение с приращением, то в этом случаем мы можем написать еще один метод, который будет просто прибавлять пробег к уже имеющемся показаниям. Для этого добавим метод add_mileage в класс Car :
Новый метод add_mileage() получает пробег в км и добавлет его к self.mileage.
car_2. add_mileage (14687)
car_2. read_mileage ()
Пробег автомобиля 31787 км.
В итоге после вызова метода add_mileage() пробег автомобиля в экземпляре car_2 увеличится на 14687 км и станет равным 31787 км. Данный метод мы можем вызывать каждый раз при изменении пробега и передавать новые значение, на которое будет увеличивать основной пробег.
3. Наследование класса в Python
class Car():
«»»Описание автомобиля»»»
def __init__(self, brand, model, years):
«»»Инициализирует атрибуты brand и model»»»
self.brand = brand
self.model = model
self.years = years
self.mileage = 0
def get_full_name(self):
«»»Автомобиль»»»
name = f»Автомобиль
return name.title()
def read_mileage(self):
«»»Пробег автомобиля»»»
print(f»Пробег автомобиля
def update_mileage(self, new_mileage):
«»»Устанавливает новое значение пробега»»»
self.mileage = new_mileage
def add_mileage(self, km):
«»»Добавляет пробег»»»
self.mileage += km
Создадим экземпляр класса ElectriCar и сохраним его в переменную tesla_1
tesla_1 = ElectricCar (‘tesla’, ‘model x’, 2021)
print(tesla_1. get_full_name ())
tesla_1. battery_power ( )
При вызове двух методов мы получим:
Автомобиль Tesla Model X 2021
Мощность аккумулятора 100 кВт⋅ч
3.1. Переопределение методов класса-родителя
Методы, которые используются в родительском классе можно переопределить в классе-потомке (подклассе). Для этого в классе-потомке определяется метод с тем же именем, что и у класса-родителя. Python игнорирует метод родителя и переходит на метод, написанный в классе-потомке (подклассе). Переопределим метод def get_full_name() чтобы сразу выводилась мощность аккумуляторов.
В результате при запросе полного названия автомобиля Python проигнорирует метод def get_full_name() в классе-родителя Car и сразу перейдет к методу def get_full_name() написанный в классе ElectricCar.
tesla_1 = ElectricCar (‘tesla’, ‘model x’, 2021)
print(tesla_1. get_full_name ())
Автомобиль Tesla Model X 2021 100-Квт⋅Ч
Как создавать классы в Python со знанием дела: разбираем на примерах
Так что Python — это (n+1)-й язык, в котором была реализована концепция ООП.
Что же такое ООП?
В какой-то момент мы поймем, что утка чем-то похожа на других птиц: значит, ее можно отнести к категории (обобщенному, родительскому классу, шаблону) «птицы». С другой стороны, для нашей игры не важно, как устроен организм утки: главное, что она как-то выглядит и как-то крякает. То есть мы абстрагируемся от ненужных для нашей модели нюансов. А кто-то другой добавит эти нюансы в свою модель и реализует, например, утиный анатомический атлас. Но некто третий использует обе модели и на их базе создаст свою. Это в двух словах о том, каким образом формируются модели и каким образом объекты подразделяются на классы.
Утка и Птица — это классы, а утка1, утка2 и птица1, птица2 — объекты (экземпляры классов).
Концепция объектно-ориентированного программирования опирается на три известных утки кита. Давайте познакомимся с ними поближе.
Инкапсуляция
Этим словом обозначают сокрытие нюансов поведения объекта или его характеристик от «посторонних» программистов. Например, над компьютерной игрой работают два программиста. Один из них реализовал класс Утка, а другой просто хочет его использовать и у них случается такой диалог:
— Какой код написать, чтобы твоя утка полетела?
Наследование
В примере выше Утка — наследник класса Птица. В то же время Птица — родительский класс по отношению к Утке. Вот так принято выражаться.
Полиморфизм
Сколько способов есть у утки, чтобы поздороваться с вами голосом? Наверное, она просто скажет что-то вроде «кря». Допустим, у нее есть один способ. Хорошо, сколько способов есть у лебедя? Они вроде как просто шипят. Допустим, тоже один. А если у птиц в целом? Ну не знаю… много. Однако все в целом по-прежнему будет называться словом «поздороваться»:
Действие называется одинаково, но выполнено оно будет по-разному — в зависимости от объекта, который это действие будет выполнять. У объекта утка1 класса Утка и у объекта лебедь1 класса Лебедь это произойдет по-разному. В буквальном переводе греческое слово polýmorphos означает «многообразный». Поняли, да?
Далее перейдем к практике и разберемся, как создавать классы и делать с ними вот это все на Python. Остальную терминологию ООП и специальные термины из Python изучим по ходу дела.
Первый класс
Ключевое слово class мы уже обсудили. Оно ставится перед названием класса, которое пишется с большой буквы. Внутри класса для начала просто выведем сообщение.
Создаем объект (он же экземпляр класса) вот так — в одну строку:
Имя объекта (здесь создан объект по имени b ) пишем с маленькой буквы. В этом случае внутри скобок нет параметров, но позже мы посмотрим, как и зачем их туда вписывать. Для второго объекта — аналогично. И вот такой результат работы этой программы мы получим:
Птица, ты кто?
Пока мы толком ничего не можем сказать о созданном объекте b. Все потому, что мы создали для него пустой класс, который просто занимается самолюбованием. Давайте это исправим. Добавим один атрибут name классу Bird.
Атрибуты — это набор данных, характеризующих объект или его состояние.
Теперь можно дать каждой птице (объекту класса Bird) имя:
Запустив программу, получим:
Чтобы получить значение атрибута, мы обращаемся к нему через имя объекта с точкой (b.name).
Ключевое слово self
По аналогии внутри него мы будем делать это вот как:
Получается, что self заменяет имя любого объекта, когда мы пишем код внутри его класса.
Если внутри Bird использовать объект другого класса, слово self для него не применяется. Например, создадим класс Cird :
Создадим и используем объект класса Cird внутри класса Bird:
Результат выполнения кода:
Конструктор и инициализатор
Теперь стало немного понятнее, зачем нужен self в этом странном методе класса:
Хорошо… но почему это так? И зачем вообще нужен этот метод?
Это инициализатор. Обычно именно здесь в атрибуты объекта записываются значения. Это могут быть значения по умолчанию (как в классе Cird: self.message = «Я объект c, класса Cird» ) или значения, полученные с использованием параметров функции.
А как же создается сам объект?
Статические и динамические атрибуты
И такое тоже практикуют. И такие атрибуты даже имеют свое название и применение:
Статические атрибуты применяются для того, чтобы иметь одну общую переменную для всех объектов класса.
Дело в том, что при создании новых объектов создаются копии всех динамических атрибутов со сброшенными к «заводским настройкам» значениями. Статические атрибуты относятся не к объекту, а к классу и имеют только одну копию.
В примере выше статический атрибут ruClassName просто хранит название класса. В примере поинтереснее статический атрибут может служить для подсчета количества созданных объектов класса:
Методы класса
Что, если нам дали задачу расширить пример из предыдущего раздела?
1. Нужно добавить Птице больше атрибутов:
2. Реализовать возможность выводить атрибут имя ( name ), а также эти два атрибута для каждого объекта класса Птица.
С первым пунктом мы справимся легко, как говорится, по образу и подобию:
Вроде бы и вывод тоже можно сделать аналогично:
Результат работы кода:
Но наш тимлид считает, что такой код некрасивый и не очень читабельный. Да и ООП рекомендует помещать код обработки данных объекта внутрь его класса. Попробуем:
Функция info() внутри класса Bird называется методом. Теперь у каждого созданного объекта этого класса можно вызвать метод:
Код действительно выглядит более лаконично. Получается, что теперь каждый объект сам может сообщить информацию о себе. И теперь, используя объект, сторонний программист может не задумываться о том, как реализован вывод информации о нем. Он работает, и хорошо!
Результат работы такой же, как в предыдущем примере:
Уровни доступа атрибута и метода
Реализация концепции ООП должна предусмотреть возможность запретить прямой доступ к атрибуту (или к методу) со стороны внешнего кода. То есть сделать его скрытым, приватным (термин из англоязычного ООП — private). Прямая модификация некоторых особо важных атрибутов может привести к дефектам в программе. Часто это нужно для того, чтобы оставлять доступ открытым («публичным», public) только к тем атрибутам и методам, которые будут взаимодействовать с внешним кодом. Остальные атрибуты и функции, которые, например, просто (или сложно) обслуживают свой класс, не должны быть доступны извне.
В Python это реализовано с помощью добавления к имени атрибута или метода одинарного или двойного подчеркивания. Первое используется в расчете на более сознательных и внимательных граждан. Второе — более жесткий вариант для всех остальных. Что это означает? Перейдем к конкретике и возьмем из нашего примера атрибут name:
По заветам ООП, и в первом, и во втором случае нужно узнать, написаны ли специальные методы для получения значения ( getter ) и/или модификации ( setter ) интересующего вас скрытого атрибута. Если да, то используйте их.
Эти методы обычно выглядят примерно так:
Перепишем весь класс:
Создадим объект и покажем правильный доступ к атрибуту _name (для __name все будет аналогично), который теперь обозначен как скрытый:
Результат работы программы:
Оказывается, мы можем переименовать созданный объект. Здорово. Но что, если нам запрещено называть птиц Иванами?
Тогда программа будет работать по-другому:
Свойства
В остальном это обычные методы.
Код вызова извне тоже изменится:
Результат работы программы останется прежним:
Начать и закончить: наследование и полиморфизм
Про наследование и полиморфизм уже шла речь в начале статьи. Но тогда нельзя было приводить полноценные примеры на Python. Теперь, когда мы подтянули матчасть, написали и много раз переписали свой первый класс… как говорится, примеры в студию! Поэтому, если вам требуется время, чтобы вернуться в начало статьи и повторить эту тему — не волнуйтесь, я подожду.
Повторили? Тогда полетели дальше.
Наследование
Оттолкнемся от нашего класса Bird. Вспомним, как он выглядит:
Создадим новый класс Duck (утка), который максимально использует код класса Bird и допишем в него немного своего кода. То есть Duck будет наследником Bird, который является родителем, базовым классом. Это в принципе ожидаемо: чтобы некая сферическая птица в вакууме стала уткой, достаточно добавить пару опознавательных знаков (потому что для примера мы придумали простую модель). Итак, пусть у класса Duck будут такие динамические атрибуты:
Атрибуты «скорость полета» и «высота полета» бессмысленно помещать в базовый класс, потому что не все птицы умеют летать:
В строке class Duck (Bird) мы в скобках указываем имя класса, от которого хотим делать наследование.
В методе def __init__ (self, name, id, age, fly_speed, fly_height) мы, помимо заполнения значений атрибутов текущего объекта класса Duck, вызываем инициализатор объекта базового класса (Bird):
super().__init__(name, id, age)
Теперь проверим, как работает это ваше наследование. Как обычно, создаем объект, заполняем его данными и просим рассказать о себе:
Отметим, что внутри метода info() у утки (см. класс Duck) мы, по аналогии с инициализатором и чисто для полноты информации — вызываем свой метод info() у базового класса (то есть у Bird):
Ну вот, у нас получилась утка, которая может рассказать о себе и при этом помнит, что она Птица — не забывает свои корни. Жирным выделены атрибуты базового класса:
Идентификационный номер: 22
Скорость полета: 110
Отлично, с уткой все получилось удачно. Но означает ли это, что можно создавать еще много аналогичных классов-наследников, используя один и тот же код базового класса? А еще интереснее узнать вот что:
super().__init__(name, id, age)
Теперь проверим, как это сработает на этот раз. Жирным выделены атрибуты, относящиеся к базовому классу:
Идентификационный номер: 22
Вид: Галапагосский баклан
Количество особей: 60
Теперь сведем воедино работу объектов всех трех классов — родителя и наследников :
Создавать такие объекты можно в любом порядке. Как видите, вообще не обязательно, чтобы объект базового класса создавался первым.
Жирным выделены атрибуты, относящиеся к базовому классу:
Идентификационный номер: 22
Вид: Галапагосский баклан
Количество особей: 60
Идентификационный номер: 9
Идентификационный номер: 77
Скорость полета: 110
Мы показали, что метод info() действительно работает по-разному — в зависимости от класса того объекта, который обращается к этому методу.
Мы применили все знания, полученные в статье, и только в конце смогли написать код в соответствии с парадигмой полиморфизма.
Надеюсь, тот, кто дочитал это до конца, получил ответ на свой вопрос!








