Определение классов
Класс определяется с помощью ключевого слова class. Синтаксис выглядит так:
class NameOfClass:
# class defition goes hereИмена классов обычно пишут в стиле PascalCase, также известном как UpperCamelCase. Это означает, что все слова в имени класса пишутся вместе, без пробелов, и каждое слово начинается с заглавной буквы. Следующие имена классов соответствуют этому соглашению:
WeekdayBankAccountLibraryDatabasePythonCourseGrades
Одно определение класса должно представлять одно целое, содержимое которого каким-то образом атомарно связано между собой. В более сложных программах классы могут содержать элементы других классов. Например, класс Course мог бы содержать объекты класса Lecture, ExerciseSession и т. д.
Давайте посмотрим на каркас определения класса. На этом этапе функциональность еще отсутствует.
class BankAccount:
passФрагмент кода выше сообщает Python, что здесь мы определяем класс с именем BankAccount. Класс пока не содержит никакой функциональности, но мы все равно можем создать объект на основе класса.
Рассмотрим программу, где к объекту BankAccount добавляются две переменные: balance и owner. Любые переменные, привязанные к объекту, называются его атрибутами, или, точнее, атрибутами данных, а иногда переменными экземпляра.
К атрибутам, привязанным к объекту, можно обращаться через объект:
class BankAccount:
pass
peters_account = BankAccount()
peters_account.owner = "Peter Python"
peters_account.balance = 5.0
print(peters_account.owner)
print(peters_account.balance)Peter Python 5.0
Атрибуты данных доступны только через объект, к которому они привязаны. У каждого объекта BankAccount, созданного на основе класса BankAccount, есть собственные значения атрибутов данных. К этим значениям можно обратиться, ссылаясь на нужный объект:
account = BankAccount()
account.balance = 155.50
print(account.balance) # This refers to the data attribute balance attached to the account
print(balance) # THIS CAUSES AN ERROR, as there is no such independent variable available, and the object reference is missingДобавление конструктора
В примере выше мы увидели, что новый экземпляр класса можно создать, вызвав метод-конструктор класса так: NameOfClass(). Затем выше мы отдельно привязали к объекту атрибуты данных, но часто удобнее передавать начальные значения этих атрибутов прямо при создании объекта. В примере выше сначала существовал объект BankAccount без этих атрибутов, и атрибуты появлялись только после явного объявления.
Объявление атрибутов вне конструктора приводит к ситуации, где разные экземпляры одного и того же класса могут иметь разные атрибуты. Следующий код вызывает ошибку, потому что теперь у нас есть другой объект BankAccount, paulas_account, который не содержит тех же атрибутов:
class BankAccount:
pass
peters_account = BankAccount()
peters_account.owner = "Peter"
peters_account.balance = 1400
paulas_account = BankAccount()
paulas_account.owner = "Paula"
print(peters_account.balance)
print(paulas_account.balance) # THIS CAUSES AN ERRORПоэтому вместо того чтобы объявлять атрибуты после создания каждого экземпляра класса, обычно лучше инициализировать значения атрибутов при вызове конструктора класса. Поскольку определение класса BankAccount сейчас является только каркасом, метод-конструктор неявно предполагается интерпретатором Python, но можно определить собственные методы-конструкторы, и именно это мы сейчас сделаем.
Метод-конструктор — это объявление метода со специальным именем __init__, обычно расположенное в самом начале определения класса.
Посмотрим на класс BankAccount с добавленным методом-конструктором:
class BankAccount:
# The constructor
def __init__(self, balance: float, owner: str):
self.balance = balance
self.owner = ownerИмя метода-конструктора всегда __init__. Обратите внимание на два подчеркивания с обеих сторон слова init.
Первый параметр в определении конструктора всегда называется self. Он ссылается на сам объект и необходим для объявления любых атрибутов, привязанных к объекту. Присваивание
self.balance = balance
присваивает баланс, полученный как аргумент, атрибуту balance объекта. Распространенное соглашение — использовать одинаковые имена переменных для параметров и атрибутов данных, определяемых в конструкторе, но имена переменных self.balance и balance выше относятся к двум разным переменным:
-
Переменная
self.balance— атрибут объекта. У каждого объектаBankAccountесть собственный баланс. -
Переменная
balance— параметр метода-конструктора__init__. Ее значение устанавливается равным значению, переданному как аргумент методу при вызове конструктора (то есть при создании нового экземпляра класса).
Теперь, когда мы определили параметры метода-конструктора, мы можем передать желаемые начальные значения атрибутов данных как аргументы при создании нового объекта:
class BankAccount:
# The constructor
def __init__(self, balance: float, owner: str):
self.balance = balance
self.owner = owner
# As the method is called, no argument should be given for the self parameter
# Python assigns the value for self automatically
peters_account = BankAccount(100, "Peter Python")
paulas_account = BankAccount(20000, "Paula Pythons")
print(peters_account.balance)
print(paulas_account.balance)100 20000
Теперь работать с объектами BankAccount гораздо проще: значения можно передавать при создании объекта, а получившиеся два отдельных экземпляра можно обрабатывать более предсказуемо и единообразно. Объявление атрибутов данных в конструкторе также гарантирует, что атрибуты действительно объявлены, а нужные начальные значения всегда заданы программистом, использующим класс.
Начальные значения атрибутов данных все еще можно изменить позже в программе:
class BankAccount:
# The constructor
def __init__(self, balance: float, owner: str):
self.balance = balance
self.owner = owner
peters_account = BankAccount(100, "Peter Python")
print(peters_account.balance)
# Change the balance to 1500
peters_account.balance = 1500
print(peters_account.balance)
# Add 2000 to the balance
peters_account.balance += 2000
print(peters_account.balance)100 1500 3500
Посмотрим еще на один пример классов и объектов. Мы напишем класс, который моделирует один розыгрыш лотерейных чисел:
from datetime import date
class LotteryDraw:
def __init__(self, round_week: int, round_date: date, numbers: list):
self.round_week = round_week
self.round_date = round_date
self.numbers = numbers
# Create a new LotteryDraw object
round1 = LotteryDraw(1, date(2021, 1, 2), [1,4,8,12,13,14,33])
# Tulostetaan tiedot
print(round1.round_week)
print(round1.round_date)
for number in round1.numbers:
print(number)1 2021-01-02 1 4 8 12 13 14 33
Как видно выше, атрибуты могут быть любого типа. Здесь у каждого объекта LotteryDraw есть атрибуты типов list и date.
Использование объектов, созданных из ваших собственных классов
Объекты, созданные из ваших собственных определений классов, ничем не отличаются от любых других объектов Python. Их можно передавать как аргументы и возвращаемые значения так же, как любой другой объект. Например, мы могли бы написать несколько вспомогательных функций для работы с банковскими счетами:
# this function creates a new bank account object and returns it
def open_account(name: str):
new_account = BankAccount(0, name)
return new_account
# this function adds the amount passed as an argument to the balance of the bank account also passed as an argument
def deposit_money_on_account(account: BankAccount, amount: int):
account.balance += amount
peters_account = open_account("Peter Python")
print(peters_account.balance)
deposit_money_on_account(peters_account, 500)
print(peters_account.balance)0 500
Текущие баллы можно посмотреть в синем индикаторе в правом нижнем углу страницы.