Как создавать объекты класса в цикле python
Перейти к содержимому

Как создавать объекты класса в цикле python

  • автор:

Создание экземпляра класса в Python

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

  • Создание нового экземпляра целевого класса;
  • Инициализация нового экземпляра с соответствующим начальным состоянием.

Для выполнения первого шага в классах Python есть специальный метод .__new__() , который отвечает за создание и возврат нового пустого объекта. Затем другой специальный метод .__init__() , принимает результирующий объект вместе с аргументами конструктора класса.

Метод .__init__() принимает новый объект в качестве первого аргумента self . Затем он устанавливает любой требуемый атрибут экземпляра в допустимое состояние, используя аргументы, переданные ему конструктором класса.

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

Чтобы изучить внутреннюю работу процесса создания экземпляров Python, рассмотрите следующий пример класса Point , который (в демонстрационных целях) реализует пользовательскую версию обоих методов, .__new__() и .__init__() :

# point.py class Point: def __new__(cls, *args, **kwargs): print("1. Создается новый экземпляр Point.") return super().__new__(cls) def __init__(self, x, y): print("2. Инициализируется новый экземпляр Point.") self.x = x self.y = y def __repr__(self) -> str: return f"type(self).__name__>(x=self.x>, y=self.y>)" 

Описание того, что делает этот код:

  • Строка def __new__(cls, *args, **kwargs) определяет метод, который принимает класс в качестве первого аргумента. Обратите внимание, что использование cls в качестве имени этого аргумента является строгим соглашением в Python, точно так же, как использование self для имени текущего экземпляра. Метод также принимает *args и **kwargs , что позволяет передавать неопределенное количество аргументов инициализации базовому экземпляру.
  • Строка return super().__new__(cls) создает и возвращает новый экземпляр Point, вызывая метод родительского класса .__new__() с cls в качестве аргумента. Этот экземпляр будет первым аргументом для .__init__() . В этом примере объект является родительским классом, и вызов super() дает доступ к нему.
  • Строка def __init__(self, x, y) определяет метод конструктора, который отвечает за этап инициализации. Этот метод принимает первый аргумент с именем self , который содержит ссылку на текущий экземпляр и два дополнительных аргумента, x и y .
  • Внутри метода конструктора .__init__() инициализируются начальные значения атрибутов экземпляра Point.x и Point.y соответственно. Для этого он использует входные аргументы x и y .

Сохраним код, представленный выше в файл с именем point.py и запустим интерпретатор Python:

>>> from point import Point >>> point = Point(21, 42) # 1. Создается новый экземпляр Point. # 2. Инициализируется новый экземпляр Point. >>> point # Point(x=21, y=42) 

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

Единственные операции, понятные объектам-экземплярам класса, являются ссылки на атрибуты класса. Существует два вида допустимых имен атрибутов класса, это атрибуты данных и методы класса.

Атрибуты данных соответствуют «переменным экземпляра» в языке Smalltalk или «членам данных» в языке C++. Атрибуты данных класса в Python можно не объявлять, как например это делается с локальным переменным, они появляться динамически, когда им впервые присваивается значение. При этом, динамически созданные атрибуты хранятся в специальном словаре объекта-экземпляра x.__dict__ . Например, если x это экземпляр MyClass , то следующий фрагмент кода напечатает значение 16 .

Создайте файл test.py с определением класса MyClass и запустите его в интерактивном режиме командой: python3 -i test.py .

# файл `test.py` class MyClass: """Простой пример класса""" i = 12345 def f(self): return 'hello world' # запускаем: $ python3 -i test.py >>> x = MyClass() # обратите внимание, что атрибут # `counter` в классе не определен >>> x.counter = 1 # динамически созданные атрибуты экземпляра класса # хранятся в специальных словарях этих экземпляров >>> x.__dict__ # >>> while x.counter  10: . x.counter = x.counter * 2 . >>> x.counter # 16 # удаляем динамически созданный атрибут >>> del x.counter # смотрим специальный словарь экземпляра >>> x.__dict__ # <> # пытаемся получить значение x.counter # Traceback (most recent call last): # File "", line 1, in # AttributeError: 'MyClass' object has no attribute 'counter' 

Другой вид ссылки на атрибут объекта-экземпляра — это метод. Метод — это функция, которая принадлежит объекту класса. В языке Python термин «метод«, для экземпляров классов, не уникален: другие типы объектов также могут иметь свои методы. Например, объекты списка list() имеют методы list.append , list.insert , list.remove , list.sort и т. д. Дальше будем использовать термин «метод» исключительно для обозначения «методов объектов экземпляра класса«, если явно не указано иное.

Допустимые имена методов объекта экземпляра класса зависят от его класса. По определению, все атрибуты класса, являющиеся объектами функций, определяют соответствующие методы его экземпляров. Таким образом, в нашем примере x.f это допустимая ссылка на связанный метод, так как MyClass.f это функция. Тогда как x.i это НЕ метод, а ссылка на атрибут класса MyClass.i . При этом выражение x.f это объект связанного метода, т.е. не то же самое, что MyClass.f . Так как MyClass.f — это объект функции.

Смотрим пример, который это показывает:

>>> MyClass.f # >>> x.f # > >>> MyClass.i # 12345 >>> x.i # 12345 
  • ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
  • Пространство имен и область видимости в классах
  • Определение классов
  • Объект класса и конструктор класса
  • Создание экземпляра класса
  • Метод экземпляра класса
  • Что такое метод класса и зачем нужен
  • Что такое статический метод в классах Python и зачем нужен
  • Атрибуты класса и переменные экземпляра класса
  • Кэширование методов экземпляра декоратором lru_cache
  • Закрытые/приватные методы и переменные класса Python
  • Наследование классов
  • Множественное наследование классов
  • Абстрактные классы
  • Перегрузка методов в классе Python
  • Что такое миксины и как их использовать
  • Класс Python как структура данных, подобная языку C
  • Создание пользовательских типов данных
  • Специальные (магические) методы класса Python
  • Базовая настройка классов Python магическими методами
  • Настройка доступа к атрибутам класса Python
  • Дескриптор класса для чайников
  • Протокол дескриптора класса
  • Практический пример дескриптора
  • Использование метода .__new__() в классах Python
  • Специальный атрибут __slots__ класса Python
  • Специальный метод __init_subclass__ класса Python
  • Определение метаклассов metaclass
  • Эмуляция контейнерных типов в классах Python
  • Другие специальные методы класса
  • Как Python ищет специальные методы в классах
  • Шаблон проектирования Фабрика и его реализация

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

Python имеет множество встроенных типов, например, int, str и так далее, которые мы можем использовать в программе. Но также Python позволяет определять собственные типы с помощью классов . Класс представляет некоторую сущность. Конкретным воплощением класса является объект.

Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики. Человек может выполнять некоторые действия — ходить, бегать, думать и т.д. То есть это представление, которое включает набор характеристик и действий, можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек будет представлять объект этого класса.

В языке Python класс определяется с помощью ключевого слова class :

class название_класса: атрибуты_класса методы_класса

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

Создадим простейший класс:

class Person: pass

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

После создания класса можно определить объекты этого класса. Например:

class Person: pass tom = Person() # определение объекта tom bob = Person() # определение объекта bob

После определения класса Person создаются два объекта класса Person — tom и bob. Для создания объекта применяется специальная функция — конструктор , которая называется по имени класса и которая возвращает объект класса. То есть в данном случае вызов Person() представляет вызов конструктора. Каждый класс по умолчанию имеет конструктор без параметров:

tom = Person() # Person() - вызов конструктора, который возвращает объект класса Person

Конструкторы

Итак, для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который не принимает параметров и который неявно имеют все классы. Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init__() (по два прочерка с каждой стороны). К примеру, изменим класс Person, добавив в него конструктор:

class Person: # конструктор def __init__(self): print("Создание объекта Person") tom = Person() # Создание объекта Person

Итак, здесь в коде класса Person определен конструктор — функция __init__ . Конструктор должен принимать как минимум один параметр ссылку на текущий объект — self . Обычно конструкторы применяются для определения действий, которые должны производиться при создании объекта.

Теперь при создании объекта:

tom = Person()

выполняется вызов конструктора __init__() из класса Person, который выведет на консоль строку «Создание объекта Person».

Стоит отметить, что конструктор фактически представляет обычную функцию, только для вызовы конструктора используется не __init__ , а название класса. Кроме того, при вызове конструктора параметру self явным образом не передается никакого значения. При выполнении программы Python динамически будет определять self .

Атрибуты объекта

Атрибуты хранят состояние объекта. Для определения и установки атрибутов внутри класса можно применять слово self . Например, определим следующий класс Person:

class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) # обращение к атрибутам # получение значений print(tom.name) # Tom print(tom.age) # 22 # изменение значения tom.age = 37 print(tom.age) # 37

Теперь конструктор класса Person принимает еще два параметра — name и age. Через эти параметры в конструктор будут передаваться имя и возраст создаваемого человека.

Внутри конструктора устанавливаются два атрибута — name и age (условно имя и возраст человека):

def __init__(self, name, age): self.name = name self.age = age

Атрибуту self.name присваивается значение переменной name. Атрибут age получает значение параметра age. Название атрибутов не обязательно должно соответствовать названиям параметров.

Если мы определили в классе конструктор __init__ с параметрами (кроме self), то при вызове конструктора этим параметрам надо передать значения:

tom = Person("Tom", 22)

То есть в данном случае параметру name передается строка «Tom», а параметру age — число 22.

Далее по имени объекта мы можем обращаться к атрибутам объекта — получать и изменять их значения:

print(tom.name) # получение значения атрибута name tom.age = 37 # изменение значения атрибута age

Подобным образом мы можем создавать разные объекты класса Person с разным значением для атрибутов:

class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) bob = Person("Bob", 43) print(tom.name) # Tom print(bob.name) # Bob

Здесь создаются два объекта класса Person: tom и bob. Они соответствуют определению класса Person, имеют одинаковый набор атрибутов, однако их состояние будет отличаться. И в каждом случае Python будет динамически определять объект self. Так, в следующем случае

tom = Person("Tom", 22)

Это будет объект tom

bob = Person("Bob", 43)

Это будет объект bob

В принципе нам необязательно определять атрибуты внутри класса — Python позволяет сделать это динамически вне кода:

class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) tom.company = "Microsoft" print(tom.company) # Microsoft

Здесь динамически устанавливается атрибут company, который хранит место работы человека. И после установки мы также можем получить его значение. В то же время подобное определение чревато ошибками. Например, если мы попытаемся обратиться к атрибуту до его определения, то программа сгенерирует ошибку:

tom = Person("Tom", 22) print(tom.company) # ! Ошибка - AttributeError: Person object has no attribute company

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

Методы класса фактически представляют функции, которые определенны внутри класса и которые определяют его поведение. Например, определим класс Person с одним методом:

class Person: # определение класса Person def say_hello(self): print("Hello") tom = Person() tom.say_hello() # Hello

Здесь определен метод say_hello() , который условно выполняет приветствие — выводит строку на консоль. При определении методов любого класса, как и конструктора, первый параметр метода представляет ссылку на текущий объект, который согласно условностям называется self . Через эту ссылку внутри класса мы можем обратиться к функциональности текущего объекта. Но при самом вызове метода этот параметр не учитывается.

Используя имя объекта, мы можем обратиться к его методам. Для обращения к методам применяется нотация точки — после имени объекта ставится точка и после нее идет вызов метода:

объект.метод([параметры метода])

Например, обращение к методу say_hello() для вывода приветствия на консоль:

tom.say_hello() # Hello

В итоге данная программа выведет на консоль строку «Hello».

Если метод должен принимать другие параметры, то они определяются после параметра self , и при вызове подобного метода для них необходимо передать значения:

class Person: # определение класса Person def say(self, message): # метод print(message) tom = Person() tom.say("Hello METANIT.COM") # Hello METANIT.COM

Здесь определен метод say() . Он принимает два параметра: self и message. И для второго параметра — message при вызове метода необходимо передать значение.

Для обращения к атрибутам и методам объекта внутри класса в его методах также применяется слово self:

self.атрибут # обращение к атрибуту self.метод # обращение к методу

Например, следующий класс Person:

class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom", 22) tom.display_info() # Name: Tom Age: 22 bob = Person("Bob", 43) bob.display_info() # Name: Bob Age: 43

Здесь определяется метод display_info(), который выводит информацию на консоль. И для обращения в методе к атрибутам объекта применяется слово self: self.name и self.age

В итоге мы получим следующий консольный вывод:

Name: Tom Age: 22 Name: Bob Age: 43

Деструкторы

Кроме конструкторов классы в Python также могут определять специальные методы — деструкторы , которые вызываются при удалении объекта. Деструктор представляет собой метод __del__(self) , в который, как и в конструктор, передается ссылка на текущий объект. В деструкторе определяются действия, которые надо выполнить при удалении объекта, например, освобождение или удаление каких-то ресурсов, которые использовал объект.

Деструктор вызывается автоматически интерпретатором, нам не нужно его явным образом вызывать. Простейший пример:

class Person: def __init__(self, name): self.name = name print("Создан человек с именем", self.name) def __del__(self): print("Удален человек с именем", self.name) tom = Person("Tom")

Здесь в деструкторе просто выведится уведомление об удалении объекта Person. Программа создает один объект Person и хранит ссылку на него в переменной tom. Создание объекта вызовет выполнение конструктора. При завершении программы автоматически будет выполняться деструктор объекта tom. В итоге консольный вывод программы будет следующим:

Создан человек с именем Tom Удален человек с именем Tom
class Person: def __init__(self, name): self.name = name print("Создан человек с именем", self.name) def __del__(self): print("Удален человек с именем", self.name) def create_person(): tom = Person("Tom") create_person() print("Конец программы")

Здесь объект Person создается и используется внутри функции create_person, поэтому жизнь создаваемого объекта Person ограничена областью этой функции. Соответственно, когда функция завершит свое выполнение, у объекта Person будет вызываться деструктор. В итоге мы получим следующий консольный вывод:

Создан человек с именем Tom Удален человек с именем Tom Конец программы

Создание классов и объектов

В языке программирования Python классы создаются с помощью инструкции class , за которой следует произвольное имя класса, после которого ставится двоеточие, далее с новой строки и с отступом реализуется тело класса:

class ИмяКласса: код_тела_класса

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

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

ИмяКласса()

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

имя_переменной = ИмяКласса()

В последствии к объекту обращаются через связанную с ним переменную.

Пример «пустого» класса и двух созданных на его основе объектов:

>>> class A: . pass . >>> a = A() >>> b = A()

Класс как пространство имен

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

>>> class B: . n = 5 . def adder(v): . return v + B.n . >>> B.n 5 >>> B.adder(4) 9

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

Класс как шаблон для создания объектов

На самом деле классы – не модули. Они своего рода шаблоны, от которых создаются объекты-экземпляры. Такие объекты наследуют от класса его атрибуты. Вернемся к нашему классу B и создадим на его основе два объекта:

>>> class B: . n = 5 . def adder(v): . return v + B.n . >>> a = B() >>> b = B()

У объектов, связанных с переменными a и b , нет собственного поля n . Однако они наследуют его от своего класса:

>>> a.n 5 >>> a.n is B.n True

То есть поля a.n и B.n – это одно и то же поле, к которому можно обращаться и через имя a , и через имя b , и через имя класса. Поле одно, ссылок на него три.

Однако что произойдет в момент присваивания этому полю значения через какой-нибудь объект-экземпляр?

>>> a.n = 10 >>> a.n 10 >>> b.n 5 >>> B.n 5

В этот момент у экземпляра появляется собственный атрибут n , который перекроет (переопределит) родительский, то есть тот, который достался от класса.

>>> a.n is B.n False >>> b.n is B.n True

При этом присвоение через B.n отразится только на b и B , но не на a :

>>> B.n = 100 >>> B.n, b.n, a.n (100, 100, 10)

Иная ситуация нас ожидает с атрибутом adder . При создании объекта от класса функция adder не наследуется как есть, а как бы превращается для объекта в одноименный метод:

>>> B.adder is b.adder False >>> type(B.adder) >>> type(b.adder)

Через имя класса мы вызываем функцию adder :

>>> B.adder(33) 133

Через имя объекта вызываем метод adder :

>>> b.adder(33) Traceback (most recent call last): File "", line 1, in TypeError: adder() takes 1 positional argument but 2 were given

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

Дело в том, что в отличии от функции в метод первым аргументом всегда передается объект, к которому применяется этот метод. То есть выражение b.adder(33) как бы преобразовывается в adder(b, 33) . Сам же b.adder как объект типа method хранит сведения, с каким классом он связан и какому объекту-экземпляру принадлежит:

>>> b.adder >

В нашем случае, чтобы вызывать adder через объекты-экземпляры, класс можно переписать так:

>>> class B: . n = 5 . def adder(obj, v): . return v + obj.n . >>> b = B() >>> b.adder(33) 38

В коде выше при вызове метода adder переменной-параметру obj присваивается объект, связанный с переменной, к которой применяется данный метод. В данном случае это объект, связанный с b . Если adder будет вызван на другой объект, то уже он будет присвоен obj :

>>> a = B() >>> a.n = 9 >>> a.adder(3) 12

В Python переменную-параметр метода, которая связывается с экземпляром своего класса, принято называть именем self. Таким образом, более корректный код будет таким:

>>> class B: . n = 5 . def adder(self, v): . return v + self.n

Можем ли мы все также вызывать adder как функцию, через имя класса? Вполне. Только теперь в функцию надо передавать два аргумента:

>>> B.adder(B, 200) 205 >>> B.adder(a, 200) 209

Здесь первым аргументом в функцию передается объект, у которого есть поле n лишь только потому, что далее к этому полю обращаются через выражение self.n .

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

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

Атрибут __dict__

В Python у объектов есть встроенные специальные атрибуты. Мы их не определяем, но они есть. Одним из таких атрибутов объекта является свойство __dict__ . Его значением является словарь, в котором ключи – это имена свойств экземпляра, а значения – текущие значения свойств.

>>> class B: . n = 5 . def adder(self, v): . return v + self.n . >>> w = B() >>> w.__dict__ <> >>> w.n = 8 >>> w.__dict__

В примере у экземпляра класса B сначала нет собственных атрибутов. Свойство n и метод adder – это атрибуты объекта-класса, а не объекта-экземпляра, созданного от этого класса. Лишь когда мы выполняем присваивание новому полю n экземпляра, у него появляется собственное свойство, что мы наблюдаем через словарь __dict__ .

В следующем уроке мы увидим, что свойства экземпляра обычно не назначаются за пределами класса. Это происходит в методах классах путем присваивание через self . Например, self.n = 10 .

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

>>> w.__dict__['m'] = 100 >>> w.__dict__ >>> w.m 100

Практическая работа

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

Курс с примерами решений практических работ:
pdf-версия

X Скрыть Наверх

Объектно-ориентированное программирование на 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 могут моделировать практически все что угодно. Создадим простой класс, который будет описывать конкретный автомобиль:

class Car ():
«»»Описание автомобиля»»»
def __init__ ( self , brand, model):
«»»Инициализирует атрибуты brand и model»»»
self .brand = brand
self .model = model

def sold ( self ):
«»»Автомобиль продан»»»
print(f»Автомобиль < self .brand> < self .model>продан «)

def discount ( self ):
«»»Скидка на автомобиль»»»
print(f»На автомобиль < self .brand> < self .model>скидка 5%»)

Разберем код по порядку. В начале определяется класс с именем Car ( class Car ). По общепринятым соглашение название класса начинается с символа верхнего регистра. Круглые скобки в определение класса пусты, так как класс создается с нуля. Далее идет строка документации с кратким описанием. ( «»»Описание автомобиля»»» ).

1.1. Метод __init__()

Функция, являющаяся частью класса, называется методом. Все свойства функций так же относятся и к методам, единственное отличие это способ вызова метода. Метод __init__() — специальный метод, который автоматически выполняется при создание нового экземпляра. Имя метода начинается и заканчивается двумя символами подчеркивания. Метод __init__() определяется с тремя параметрами: self, brand, model. Параметр self обязателен в определение метода и должен стоять перед всеми остальными параметрами. При создании экземпляра на основе класса Car, необходимо передать только два последних аргумента brand и model.

Каждая из двух переменных self.brand = brand и self.model = model снабжена префиксом self и к ним можно обращаться вызовом self.brand и self.model. Значения берутся из параметров brand и model. Переменные, к которым вы обращаетесь через экземпляры, также называются атрибутами.

В классе Car также есть два метода: sold() и discount() . Этим методам не нужна дополнительная информация и они определяются с единственным параметром self. Экземпляры, которые будут созданы на базе этого класса смогут вызывать данные методы, которые просто выводят информацию.

1.2. Создание экземпляра класса

С помощью класса Car мы можем создавать экземпляры для конкретного автомобиля. Каждый экземпляр описывает конкретный автомобиль и его параметры.

car_1 = Car (‘Bmw’, ‘X5’)

Создадим переменную car_1 и присвоим ей класс с параметрами автомобиля которые нужно обязательно передать (brand, model). При выполнение данного кода Python вызывает метод __init__ , создавая экземпляр, описывающий конкретный автомобиль и присваивает атрибутам brand и model переданные значения. Этот экземпляр сохраняется в переменной car_1.

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

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

class Car ():
«»»Описание автомобиля»»»
def __init__ ( self , brand, model, years):
«»»Инициализирует атрибуты»»»
self .brand = brand
self .model = model
self .years = years
self .mileage = 0

def read_mileage ( self ):
«»»Пробег автомобиля»»»
print(f»Пробег автомобиля < self .mileage>км.»)

В описание автомобиля есть три атрибута(параметра) это 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() который будет изменять показания пробега.

class Car ():
«»»Описание автомобиля»»»
def __init__ ( self , brand, model, years):
«»»Инициализирует атрибуты»»»
self .brand = brand
self .model = model
self .years = years
self .mileage = 0

def read_mileage ( self ):
«»»Пробег автомобиля»»»
print(f»Пробег автомобиля < self .mileage>км.»)

def update_mileage ( self , new_mileage):
«»»Устанавливает новое значение пробега»»»
self .mileage = new_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 :

def add_mileage (self, km):
«»»Добавляет пробег»»»
self .mileage += km

Новый метод add_mileage() получает пробег в км и добавлет его к self.mileage.

car_2. add_mileage (14687)
car_2. read_mileage ()

Пробег автомобиля 31787 км.

В итоге после вызова метода add_mileage() пробег автомобиля в экземпляре car_2 увеличится на 14687 км и станет равным 31787 км. Данный метод мы можем вызывать каждый раз при изменении пробега и передавать новые значение, на которое будет увеличивать основной пробег.

3. Наследование класса в Python

Создавая новые классы не обязательно их создавать с нуля. Новый класс может наследовать свои атрибуты (переменные) и методы (функции принадлежащие классам) от ранее определенного исходного класса ( суперкласса ). Также исходный класс называют родителем, а новый класс — потомком или подклассом. В класс-потомок можно добавлять собственные атрибуты и методы. Напишем новый класс ElectricCar, который будет создан на базе класса Car:

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

class ElectricCar ( Car ):
«»»Описывает электромобиль»»»
def __init__ ( self , brand, model, years):
«»»Инициализирует атрибуты класса родителя»»»
super().__init__ (brand, model, years)
# атрибут класса-потомка
self .battery_size = 100

def battery_power ( self ):
«»»Выводит мощность аккумулятора авто»»»
print(f»Мощность аккумулятора < self .battery_size>кВт⋅ч»)

Мы создали класс ElectriCar на базе класса Car . Имя класса-родителя в этом случае ставится в круглые скобки( class ElectricCar ( Car ) ). Метод __init__ в классе потомка (подклассе) инициализирует атрибуты класса-родителя и создает экземпляр класса Car . Функция super() .- специальная функция, которая приказывает Python вызвать метод __init__() родительского класса Car , в результате чего экземпляр ElectricCar получает доступ ко всем атрибутам класса-родителя. Имя super как раз и происходит из-за того, что класс-родителя называют суперклассом, а класс-потомок — подклассом.

Далее мы добавили новый атрибут self .battery_size и присвоили исходное значение 100. Этот атрибут будет присутствовать во всех экземплярах класса ElectriCar . Добавим новый метод battery_power() , который будет выводить информацию о мощности аккумулятора.

Создадим экземпляр класса 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 кВт⋅ч

В новый класс ElectriCar мы можем добавлять любое количество атрибутов и методов связанных и не связанных с классом-родителем Car .

3.1. Переопределение методов класса-родителя

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

class ElectricCar ( Car ):
«»»Описывает электромобиль»»»
def __init__ ( self , brand, model, years):
«»»Инициализирует атрибуты класса родителя»»»
super().__init__ (brand, model, years)
# атрибут класса-потомка
self .battery_size = 100

def battery_power ( self ):
«»»Выводит мощность аккумулятора авто»»»
print(f»Мощность аккумулятора < self .battery_size>кВт⋅ч»)

В результате при запросе полного названия автомобиля 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-Квт⋅Ч

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

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