Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Python. Учебное пособие.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
print(Pterodactyl)
>> <class '__main__.Pterodactyl'>
Язык Python превращает определение класса Pterodactyl в объект, ко-
торый можно использовать в программе, например, распечатав его. Следующий пример аналогичен предыдущему:
class Square: pass
print(Square)
>> <class '__main__.Square'>
Здесь выводится объект, которым является класс Square.

Переменные класса и переменные экземпляра класса

Классы могут иметь два типа переменных – переменные класса и пере-
менные экземпляра класса. Все переменные, которые встречались до сих пор,
были переменными экземпляра класса, определяемыми синтаксисом:
self.[имя_переменной] = [значение_переменной].
Переменные экземпляра класса принадлежат объекту, который их создал:
class Liger: def __init__ (self, name):
self.name = name connor = Liger("Connor") print(connor.name)
>> Connor
Переменные класса принадлежат как классу, который их создал, так и объ-
екту. Это означает, что можно получить к ним доступ с помощью объекта клас­са, который Python создает для каждого класса:
class Liger: interests = ["swimming", "eating", "sleeping"] def __init__ (self, name): self.name = name print(Liger.interests)
>> ['swimming', 'eating', 'sleeping']
101
В этом примере не создавался объект Liger, но можно получить доступ к переменной класса Interest. Это связано с тем, что к переменным класса может обращаться создавший их класс. Переменные класса также могут быть
доступны объекту:
class Liger: interests = ["swimming", "eating", "sleeping"] def __init__ (self, name): self.name = name larry = Liger("Larry") print(larry.interests)
>> ['swimming', 'eating', 'sleeping']
Переменные класса полезны, когда нужно, чтобы каждый объект в классе имел доступ к переменной. В этом случае имя каждого Лигера может быть уни­кальным, но все Лигеры должны иметь доступ к одному и тому же списку ин­тересов.
Для лучшего восприятия материала продемонстрируем обсуждаемые по­нятия на ставших уже классическими примерах, связанных с геометрическими фигурами:
class Rectangle(): def __init__(self, w, l):
self.width = w self.len = l def print_size(self): print("""{} на {} """.format(self.width,8 self.len)) my_rectangle = Rectangle(10, 24) my_rectangle.print_size()
>> 10 на 24
Здесь переменными экземпляра класса являются width и len.
Переменные класса принадлежат объекту, который Python создает для каждого определения класса, и объектам, которые они создают. Переменные
102
класса определяются как обычные переменные (но определение осуществляет­ся внутри класса). Можно получить к ним доступ с помощью объектов класса и объектов, созданных объектами класса, как и к переменным экземпляра, до­бавляя перед именем переменной self. Переменные класса полезны – они позволяют обмениваться данными между всеми экземплярами класса без пола­гания на глобальные переменные:
class Rectangle(): recs = [] def __init__(self, w, l): self.width = w self.len = l self.recs.append((self.width, self.len)) def print_size(self): print("""{} на {} """.format(self.width, self.len)) r1 = Rectangle(10, 24) r2 = Rectangle(20, 40) r3 = Rectangle(100, 200) print(Rectangle.recs)
>> [(10, 24), (20, 40), (100, 200)]
В этом фрагменте добавили переменную recs в класс Rectangle. Опре-
делили ее вне метода __init__, поскольку этот метод вызывается только при создании объекта, а нужно получить доступ к переменной класса, используя объект класса (что не вызывает метод __init__).
Затем были созданы три объекта Rectangle. Каждый раз, как создается
объект Rectangle, код в методе __init__ присоединяет кортеж, содержа­щий ширину и длину нового объекта, к списку recs. С помощью этого кода каждый новый объект Rectangle автоматически добавляется в список recs. Благодаря использованию переменной класса можно обменяться данными
между различными объектами, созданными классом, без необходимости ис­пользовать глобальную переменную.
103

Приватные переменные

Большинство языков программирования имеют концепцию приватных (за­крытых) переменных и методов. Это специальные переменные и методы, кото­рые может создать разработчик класса и к которым объект имеет доступ, но программист, использующий объект, не имеет доступа. В одной ситуации при­ватные переменные и методы полезны, если есть метод или переменная в клас­се, которые класс использует внутри, но планируется позже изменить реализа­цию своего кода (или нужно сохранить гибкость, чтобы иметь возможность), и, следовательно, не хотят, чтобы тот, кто использует класс, полагался на эти переменные и методы, используемые внутри, потому что они могут измениться (и затем нарушить код).
В отличие от других языков Python не имеет приватных переменных. Пе­ременные, которые не являются приватными, называются общедоступными, и все переменные Python являются общедоступными. Python решает проблему, которую приватные переменные решают другим способом – используя согла­шение. В Python, если есть переменная или метод, к которым вызывающий не должен обращаться, то ставят перед ее именем символ подчеркивания. Про­граммисты Python знают, что если у метода или переменной есть символ под­черкивания, им не следует его использовать, хотя можно это делать на свой страх и риск. Вот пример класса, который использует это соглашение:
class PublicPrivateExample: def __init__ (self): self.public_variable = "callers know they can
access this" self_dontusethisvariable ="callers know they shouldn’t access
this"
def public_method(self):
# callers know they can use this method pass
def _dont_use_this_method(self):
# callers know they shouldn’t use this method pass
104
Программисты Python, читающие этот код, будут знать, что
self.public_variable безопасно использовать, но им не следует исполь­зовать self._dontusethisvariable, а если они это делают, то делают это на свой страх и риск, потому что человек, поддерживающий этот код, не обязан хранить self._dontusethisvariable, так как вызывающие абоненты не должны иметь к ней доступ. То же самое касается двух методов: программисты Python знают, что public_method безопасно использовать, а _dont_use_this_method – нет.

Методы переопределения

Переопределением метода (англ. Method overriding) в ООП называется возможность языка программирования, позволяющая дочернему классу обес­печивать специфическую реализацию метода, уже реализованного в одном из родительских классов.
Таким образом, когда класс наследует родительский метод, есть возмож­ность переопределить его.
Пример:
class Mammal: def __init__ (self, name):
self.hunger = 100 self.tired = 100 self.name = name def print_result(self, amount, action): print("{} {} decreased by
{}.".format(self.name,
action, amount)) def eat(self, decrease): self.hunger -= decrease self.print_result(decrease, 'hunger') def sleep(self, decrease): self.tired -= decrease self.print_result(decrease, 'tiredness')
class Dolphin(Mammal): pass
105
class Tiger(Mammal): def sleep(self ,decrease):
self.tired -= decrease print("The tiger is really tired!") dolphin = Dolphin('dolphin') dolphin.eat(10) dolphin.sleep(10) tiger = Tiger('tiger') tiger.eat(10)
tiger.sleep(10) >> dolphin hunger decreased by 10. >> dolphin tiredness decreased by 10. >> tiger hunger decreased by 10. >> The tiger is really tired!
В программе были созданы два класса, которые наследуются от Mammal. Первый класс Dolphin наследует всю свою функциональность от родитель­ского класса Mammal без внесения каких-либо изменений. Второй класс Tiger определяет метод, называемый sleep, с функциональностью, отличной от ме­тода sleep, который он унаследовал от своего родительского класса. Когда вызывается tiger.sleep, вместо унаследованного метода вызывается новый метод, который определили. Помимо этого, Tiger и Dolphin обладают всеми теми же функциональными возможностями, унаследованными от родительско­го класса Mammal.

Функция super

Встроенная суперфункция позволяет вызывать метод класса, унаследован­ный от его родителя. Синтаксис:
super().[parent_method]([параметры]),
где parent_method заменяете родительским методом, который хотите вы- звать, и передаете ему любые необходимые параметры. Затем вызывается и вы­полняется родительский метод, а остальная часть кода в методе, из которого был вызван super, завершает выполнение. Вот пример того, как можно вы­звать метод sleep родительского класса Mammal из метода sleep классов
106
Tiger, чтобы использовать код из метода sleep класса Mammal с последую- щей дополнительной функциональностью:
class Tiger(Mammal): def sleep(self, decrease):
super().sleep(decrease) print("The tiger is really tired!") tiger = Tiger('tiger') tiger.eat(10)
tiger.sleep(10) >> tiger tiredness decreased by 10. >> The tiger is really tired!
Сначала используется ключевое слово super для вызова метода sleep
родительского класса Mammal и передается переменная уменьшения в качестве параметра. Выполняется метод сна млекопитающего и выводится надпись «усталость тигра уменьшилась на 10». Затем метод сна классов Tiger выпол­няет новую функциональность, которую добавили в метод сна классов Tiger, и выводит сообщение «Тигр действительно устал!». Используя ключевое слово super, вы смогли предоставить дочернему классу функциональность из мето­да родительского класса без необходимости повторно вводить функциональ­ность в дочернем классе. Это важно, потому что всегда нужно избегать повто­рения кода с одной и той же функциональностью в разных местах вашей про­граммы, когда это возможно.

Переопределение встроенных методов

Каждый класс в Python автоматически наследуется от родительского класса
с именем Object. Все классы в Python наследуют методы от этого родительско­го класса. Встроенные функции Python используют эти методы, называемые ма­гическими методами, в разных ситуациях, например при печати объекта:
class Lion:
def __init__ (self, name):
self.name = name
lion = Lion("Dilbert")
print(lion) >> <__main__.Lion object at 0x101178828>
107
При печати объекта Lion Python вызывает магический метод __repr__
для объекта, который он унаследовал от родительского класса Object. Он пе­чатает все, что возвращает метод __repr__. Можно переопределить этот встроенный метод, чтобы изменить то, что происходит, когда функция печати
печатает объект:
class Lion: def __init__ (self, name): self.name = name def __repr__ (self): return self.name lion = Lion("Dilbert") print(lion)
>> Dilbert
Поскольку метод __repr__ был переопределен, то при печати объекта
Lion имя объекта Lion – Dilbert печатается вместо чего-то вроде <__main__.Lion object at 0x101178828>, которое вернул бы унасле-
дованный метод __repr__.
Не все магические методы передаются по наследству. Такие выражения, как 2 + 2, предполагают, что операнды имеют метод, который оператор может использовать для вычисления выражения. В примере 2 + 2 целочисленные объ­екты имеют метод __add__, который вызывается при вычислении выражения,
но __add__ не наследуется при создании класса. Можно создавать объекты, которые затем используют в качестве операндов в выражении с оператором сложения, определяя метод __add__ классе:
class AlwaysPositive: def __init__ (self, number):
self.number = number
def __add__ (self, other): return abs(self.number + other.number)
x = AlwaysPositive(-20) y = AlwaysPositive(10) print (x + y)
>> 10
108
Объекты AlwaysPositive можно использовать в качестве операндов
в выражении с оператором сложения, потому что определен метод с именем __add__. Метод должен принимать второй параметр, поскольку при вычисле­нии выражения с оператором сложения __add__ вызывается для первого объ­екта операнда, а второй объект операнда передается в __add__ в качестве па­раметра. Затем выражение возвращает результат __add__ .
В этом примере использовали функцию abs для возврата абсолютного
значения двух сложенных вместе чисел. Поскольку определили __add__ та­ким образом, что два объекта AlwaysPositive, сложенные вместе, всегда будут возвращать абсолютное значение суммы двух объектов, то результат вы-
ражения всегда будет положительным.

12. Создание игр

В этой главе будем использовать то, что узнали о классах и объектах для
создания карточной игры «War». War – это игра, в которой каждый игрок берет карту из колоды, и побеждает игрок с самой старшей картой. Создадим War, определив класс, представляющий карту, колоду, игрока и, наконец, класс, представляющий саму игру. Эти классы будут работать вместе, чтобы создать игру War.

Карты

Сначала определим класс карты:
class Card: suits = ["spades", "hearts", "diamonds", "clubs"] values = [None, None, "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King", "Ace"] def __init__ (self, value, suit): """suit and value should be integers""" self.value = value self.suit = suit
109
def __lt__ (self, other): if self.value < other.value: return True if self .value == other.value: if self .suit < other.suit: return True else: return False return False def __gt__ (self, other): if self.value > other.value: return True if self.value == other.value: If self.suit > other.suit: return True else: return False return False def __repr__ (self): return self.values[self.value] + " of " +
self.suits[self.suit]
Класс Card имеет две переменные класса: suit и values. suits – это список строк, представляющих все возможные масти карты. values – это спи- сок строк, представляющих различные числовые значения, которые может иметь карта. Первые два индекса значений равны None, чтобы строки в списке совпадали с индексом, который они представляют, другими словами, чтобы строка «2» в values располагалась по индексу 2.
Класс Card также имеет две переменные экземпляра: suit и values, каждая из которых представлена целым числом. Определяют, к какому типу карт относится объект Card. Например, можно создать двойку червей, создав объект Card и передав параметры 2 и 1 (1 представляет червы, потому что червы находятся под индексом один в списке мастей). Позже объект Card бу- дет использовать эти переменные для вывода информации о том, что это за кар­та, используя их в качестве индексов в списках мастей и значений.
110
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]