Содержание
Памятка: ключевые правила именования классов в Python
- Используйте CamelCase (CapWords) для всех классов.
- Начинайте название класса с заглавной буквы.
- Не используйте нижние подчеркивания между словами.
- Избегайте сокращений и аббревиатур, если они не общеприняты.
- Название должно быть существительным или именной группой.
- Не дублируйте тип объекта в названии (избегайте суффиксов ‘Class’, ‘Object’).
- Для исключений используйте суффикс ‘Error’ или ‘Exception’.
- Для абстрактных классов можно использовать префикс ‘Abstract’ или ‘Base’.
- Не используйте зарезервированные слова и встроенные имена.
- Следуйте единому стилю во всем проекте.
- Для внутренних классов (вложенных) применяйте те же правила.
- Избегайте слишком длинных названий (более 3-4 слов).
Синтаксис и правила создания классов¶
class Person: # Объявления класса def __init__(self, name, age): # Метод инициализации = age # Установка значений атрибутов = name
Также в классах могут быть использованы встроенные методы, их называют магическими. Магические методы — зарезервированные методы, отвечающие за поведение объекта.
Таблица №1
|
Название |
Применение |
|---|---|
|
|
Инициализация объекта |
|
|
Преобразование к строке str(obj) |
|
|
Проверка на равенство |
|
|
Оператор доступа к элементам |
some_dict[‘item’] |
|
class Person: # Объявления класса def __init__(self, name, age): # Метод инициализации = age # Установка значений атрибутов = name def __str__(self): return f»{} is {} years old» person = Person(‘John’, 20) # Создание экземпляра = ‘James’ # Установка значения атрибута print(person)
Создание Класса
# Python 2.x syntax class Vehicle(object): «»»docstring»»» def __init__(self): «»»Constructor»»» pass
Таблица №2
|
1
2
3
4
5
6
7
8
|
# Python 2.x syntax
class Vehicle(object):
«»»docstring»»»
def __init__(self):
«»»Constructor»»»
pass
|
Этот класс не делает ничего конкретного, тем не менее, это очень хороший инструмент для изучения. Например, чтобы создать класс, мы используем ключевое слово class, за которым следует наименование класса. В Пайтоне, конвенция указывает на то, что наименование класса должно начинаться с заглавной буквы. Далее нам нужно открыть круглые скобки, за которыми следует слово object и закрытые скобки. «object» — то, на чем основан класс, или наследуется от него. Это называется базовым классом или родительским классом. Большая часть классов в Пайтоне основаны на объекте. У классов есть особый метод, под названием __init__.
Этот метод вызывается всякий раз, когда вы создаете (или создаете экземпляр) объект на основе этого класса. Метод __init__ вызывается единожды, и не может быть вызван снова внутри программы. Другое определение метода __init__ — это конструктор, кстати, этот термин редко встречается в Пайтоне. Вы можете подумать, почему я называю это методом, а не функцией? Функция меняет свое имя на «method», когда она находится внутри класса. Обратите внимание на то, что каждый метод должен иметь как минимум один аргумент, что в случае с обычной функцией уже не вяжется. В Python 3 нам не нужно прямо указывать, что мы наследуем у объекта. Вместо этого, мы можем написать это следующим образом:
# Python 3.x syntax class Vehicle: «»»docstring»»» def __init__(self): «»»Constructor»»» pass
Таблица №3
|
1
2
3
4
5
6
7
8
|
# Python 3.x syntax
class Vehicle:
«»»docstring»»»
def __init__(self):
«»»Constructor»»»
pass
|
Обратите внимание на то, что единственная разница в том, что круглые скобки нам больше не нужны, когда мы основываем наш класс на объекте. Давайте немного расширим наше определение класса и дадим ему некоторые атрибуты и методы.
class Vehicle(object): «»»docstring»»» def __init__(self, color, doors, tires): «»»Constructor»»» = color = doors = tires def brake(self): «»» Stop the car «»» return «Braking» def drive(self): «»» Drive the car «»» return «I’m driving!»
Таблица №4
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class Vehicle(object):
«»»docstring»»»
def __init__(self, color, doors, tires):
«»»Constructor»»»
self.color = color
self.doors = doors
self.tires = tires
def brake(self):
«»»
Stop the car
«»»
return «Braking»
def drive(self):
«»»
Drive the car
«»»
return «I’m driving!»
|
В данном примере мы добавили три атрибута и два метода. Эти три атрибута являются:
Таблица №5
|
1
2
3
|
self.color = color
self.doors = doors
self.tires = tires
|
Атрибуты описывают автомобиль. У него есть цвет, определенное количество дверей и колес. Также у него есть два метода. Метод описывает, что делает класс. В нашем случае, автомобиль может двигаться и останавливаться. Вы могли заметить, что все методы, включая первый, имеют интересный аргумент, под названием self. Давайте рассмотрим его внимательнее.
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!
Что такое self?
Классам нужен способ, что ссылаться на самих себя. Это не из разряда нарциссичного отношения со стороны класса. Это способ сообщения между экземплярами. Слово self это способ описания любого объекта, буквально. Давайте взглянем на пример, который мне кажется наиболее полезным, когда я сталкиваюсь с чем-то новым и странным: Добавьте этот код в конец класса, который вы написали ранее и сохраните:
class Vehicle(object): «»»docstring»»» def __init__(self, color, doors, tires): «»»Constructor»»» = color = doors = tires def brake(self): «»» Stop the car «»» return «Braking» def drive(self): «»» Drive the car «»» return «I’m driving!» if __name__ == «__main__»: car = Vehicle(«blue», 5, 4) print() truck = Vehicle(«red», 3, 6) print()
Таблица №6
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class Vehicle(object):
«»»docstring»»»
def __init__(self, color, doors, tires):
«»»Constructor»»»
self.color = color
self.doors = doors
self.tires = tires
def brake(self):
«»»
Stop the car
«»»
return «Braking»
def drive(self):
«»»
Drive the car
«»»
return «I’m driving!»
if __name__ == «__main__»:
car = Vehicle(«blue», 5, 4)
print(car.color)
truck = Vehicle(«red», 3, 6)
print(truck.color)
|
Условия оператора if в данном примере это стандартный способ указать Пайтону на то, что вы хотите запустить код, если он выполняется как автономный файл. Если вы импортировали свой модуль в другой скрипт, то код, расположенный ниже проверки if не заработает. В любом случае, если вы запустите этот код, вы создадите два экземпляра класса автомобиля (Vehicle): класс легкового и класс грузового. Каждый экземпляр будет иметь свои собственные атрибуты и методы. Именно по этому, когда мы выводи цвета каждого экземпляра, они и отличаются друг от друга. Причина в том, что этот класс использует аргумент self, чтобы указать самому себе, что есть что. Давайте немного изменим класс, чтобы сделать методы более уникальными:
class Vehicle(object): «»»docstring»»» def __init__(self, color, doors, tires, vtype): «»»Constructor»»» = color = doors = tires = vtype def brake(self): «»» Stop the car «»» return «%s braking» % def drive(self): «»» Drive the car «»» return «I’m driving a %s %s!» % (,) if __name__ == «__main__»: car = Vehicle(«blue», 5, 4, «car») print(()) print(()) truck = Vehicle(«red», 3, 6, «truck») print(()) print(())
Таблица №7
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
class Vehicle(object):
«»»docstring»»»
def __init__(self, color, doors, tires, vtype):
«»»Constructor»»»
self.color = color
self.doors = doors
self.tires = tires
self.vtype = vtype
def brake(self):
«»»
Stop the car
«»»
return «%s braking» % self.vtype
def drive(self):
«»»
Drive the car
«»»
return «I’m driving a %s %s!» % (self.color, self.vtype)
if __name__ == «__main__»:
car = Vehicle(«blue», 5, 4, «car»)
print(car.brake())
print(car.drive())
truck = Vehicle(«red», 3, 6, «truck»)
print(truck.drive())
print(truck.brake())
|
В этом примере мы передаем другой параметр, чтобы сообщить классу, какой тип транспортного средства мы создаем. После этого мы вызываем каждый метод для каждого экземпляра. Если вы запустите данный код, вы получите следующий вывод:
car braking I’m driving a blue car! I’m driving a red truck! truck braking
Таблица №8
|
1
2
3
4
|
car braking
I‘m driving a blue car!
I’m driving a red truck!
truck braking
|
Это показывает, как экземпляр отслеживает свой аргумент self. Вы также могли заметить, что мы можем переместить переменные атрибутов из метода __init__ в другие методы. Это возможно потому, что все эти атрибуты связанны с аргументом self. Если бы мы этого не сделали, переменные были бы вне области видимости в конце метода __init__.
Подклассы
Настоящая сила классов становится очевидной, когда вопрос касается подклассов. Вы, возможно, еще не поняли это, но мы уже создали подкласс, когда создавали класс, основанный на объекте. Другими словами, «подклассифицировали» объект. Так как объект – это не очень интересная тема, предыдущие примеры не уделили должного внимания такому сильному инструменту как подкласс. Давайте подклассифицируем наш класс Vehicle и узнаем, как все это работает.
class Car(Vehicle): «»» The Car class «»» #———————————————————————- def brake(self): «»» Override brake method «»» return «The car class is breaking slowly!» if __name__ == «__main__»: car = Car(«yellow», 2, 4, «car») () ‘The car class is breaking slowly!’ () «I’m driving a yellow car!»
Таблица №9
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Car(Vehicle):
«»»
The Car class
«»»
#———————————————————————-
def brake(self):
«»»
Override brake method
«»»
return «The car class is breaking slowly!»
if __name__ == «__main__»:
car = Car(«yellow», 2, 4, «car»)
car.brake()
‘The car class is breaking slowly!’
car.drive()
«I’m driving a yellow car!»
|
В этом примере, мы подклассифицировали класс Vehicle. Вы могли заметить, что мы не использовали методы __init__ и drive. Причина в том, что когда мы хотим сделать из класса подкласс, мы уже имеем все атрибуты и методы, только если мы не переопределяем их. Таким образом, вы могли заметить, что мы переопределяем метод brake и указываем ему делать кое-что другое. Другие методы остаются такими же, какими они и были до этого. Так что, когда вы указываете автомобилю тормозить, он использует оригинальный метод, и мы узнали, что мы водим желтый автомобиль. Когда мы используем значения родительского класса по умолчанию – мы называем это наследование.
Это достаточно большой раздел в объектно-ориентированном программировании. Это также простой пример полиморфизма. Полиморфические классы имеют одинаковый интерфейс (методы, атрибуты), но они не контактируют друг с другом. Касаемо полиморфизма в Пайтоне, не очень сложно выяснить, что интерфейсы являются идентичными. С этого момента мы знакомимся с понятием утиная типизация. Суть утиной типизации заключается в том, что если это ходит как утка, и крякает как утка – значит, это должна быть утка.
Класс как пространство имен
С точки зрения пространства имен класс можно представить подобным модулю. Также как в модуле в классе могут быть свои переменные со значениями и функции. Также как в модуле у класса есть собственное пространство имен, доступ к которому возможен через имя класса:
>>> class B:… n = 5… def adder(v):… return v + B.n… >>> B.n 5 >>> (4) 9
Однако в случае классов используется особая терминология. Пусть имена, определенные в классе, называются атрибутами этого класса. В примере имена n и adder – это атрибуты класса B. Атрибуты-переменные часто называют полями или свойствами (в других языках понятия «поле» и «свойство» не совсем одно и то же). Полем является n. Атрибуты-функции называются методами. Методом в классе B является adder. Количество свойств и методов в классе может быть любым.
Атрибут __dict__
В Python у объектов есть встроенные специальные атрибуты. Мы их не определяем, но они есть. Одним из таких атрибутов объекта является свойство __dict__. Его значением является словарь, в котором ключи – это имена собственных свойств экземпляра, а значения – текущие значения свойств. Можно сказать, __dict__ ‒ это атрибут об атрибутах, он хранит в себе перечень имен других атрибутов объекта.
>>> class B:… n = 5… def adder(self, v):… return v + self.n… >>> w = B() >>> w.__dict__ {} >>> w.n = 8 >>> w.__dict__ {‘n’: 8}
В примере у экземпляра класса B сначала нет собственных атрибутов. Свойство n и метод adder – это атрибуты объекта-класса, а не объекта-экземпляра, созданного от этого класса. Лишь когда мы выполняем присваивание новому полю n экземпляра, у него появляется собственное свойство, что мы наблюдаем через словарь __dict__.
В следующем уроке мы увидим, что свойства экземпляра обычно не назначаются за пределами класса. Это происходит в методах классах путем присваивание через self. Например, self.n = 10.
Атрибут __dict__ используется не только для просмотра свойств объекта. С его помощью можно удалять, добавлять свойства, а также изменять их значения.
>>> w.__dict__[‘m’] = 100 >>> w.__dict__ {‘n’: 8, ‘m’: 100} >>> w.m 100
Практическая работа
Напишите программу по следующему описанию. Есть класс «Воин». От него создаются два экземпляра-юнита. Каждому устанавливается здоровье в 100 очков. В случайном порядке они бьют друг друга. Тот, кто бьет, здоровья не теряет. У того, кого бьют, оно уменьшается на 20 очков от одного удара. После каждого удара надо выводить сообщение, какой юнит атаковал, и сколько у противника осталось здоровья. Как только у кого-то заканчивается ресурс здоровья, программа завершается сообщением о том, кто одержал победу.
Часто задаваемые вопросы о нейминге классов в Python
Вопрос: Какое соглашение об именовании классов в Python является стандартом?
Ответ: Стандартом является CamelCase (CapWords) — каждое слово в названии класса пишется с заглавной буквы, без разделителей.
Вопрос: Можно ли использовать нижние подчеркивания в названиях классов?
Ответ: Технически да, но по PEP 8 это не рекомендуется. Исключение — классы, которые должны быть совместимы с другими языками или системами.
Вопрос: Как правильно называть класс, который содержит только статические методы?
Ответ: Используйте обычный CamelCase. Если класс не предназначен для создания экземпляров, рассмотрите возможность использования модуля или класса с декоратором @staticmethod.
Вопрос: Нужно ли добавлять суффикс ‘Class’ в название класса?
Ответ: Нет, это избыточно. Название должно отражать суть объекта, а не его тип. Например, ‘Car’, а не ‘CarClass’.
Вопрос: Как назвать класс, который является исключением (Exception)?
Ответ: Добавьте суффикс ‘Error’ или ‘Exception’ в конце названия, например, ‘ValidationError’ или ‘CustomException’.
Вопрос: Можно ли называть класс с маленькой буквы?
Ответ: По PEP 8 — нет. Имена классов должны начинаться с заглавной буквы. Исключение — встроенные классы Python (например, int, str).
Вопрос: Как назвать абстрактный класс?
Ответ: Используйте CamelCase. Можно добавить префикс ‘Abstract’ или ‘Base’, например, ‘AbstractAnimal’ или ‘BaseModel’.
Вопрос: Влияет ли название класса на его производительность?
Ответ: Нет, название класса никак не влияет на производительность. Это исключительно вопрос читаемости и поддержки кода.
Вопрос: Как назвать класс, который реализует паттерн ‘Одиночка’ (Singleton)?
Ответ: Используйте обычный CamelCase. Название должно отражать суть объекта, а не паттерн. Например, ‘DatabaseConnection’, а не ‘SingletonDatabase’.
Вопрос: Что делать, если название класса состоит из аббревиатуры?
Ответ: Если аббревиатура короткая (до 3 букв), пишите её заглавными: ‘HTTPServer’. Если длинная — только первую букву: ‘XmlParser’.























