Добавление функций в классы Python
Классы в Python могут создаваться просто как коллекции функций. Функции могут быть определены внутри класса обычным образом, так же как и внутри любой программы. А вот для вызова такой функции нужно действовать через данный класс. Таким образом, приведенный ниже пример класса с именем Greetings принимает имя и возвращает приветствие человеку, вызывающему этот класс.
class Greetings: def good_morning(name): print(f'Good morning {name}') def good_afternoon(name): print(f'Good afternoon {name}') def good_evening(name): print(f'Good evening {name}') Greetings.good_afternoon('John') Greetings.good_morning('Peter') Greetings.good_evening('Jane')
Результат:
Good afternoon John Good morning Peter Good evening Jane
Распространенная ошибка
Пока данный класс ведет себя так как мы и планировали. Но давайте теперь добавим в него магический метод __init__.
class Greetings: def __init__(self): pass def good_morning(name): print(f'Good morning {name}') def good_afternoon(name): print(f'Good afternoon {name}') def good_evening(name): print(f'Good evening {name}') g = Greetings()
Мы также создали экземпляр класса Greeting и поместили его в переменную g. Если мы попытаемся вызвать функцию класса как в прошлый раз, только через экземпляр класса, то получим следующую ошибку:
g.good_afternoon('John') # Результат: # TypeError: good_afternoon() takes 1 positional argument but 2 were given
Может быть не вполне понятно, что сейчас произошло. Возвращенная выше ошибка TypeError сообщает, что мы передали функции 2 аргумента вместо одного. А с виду кажется, что был передан только один аргумент. Чтобы понять, что произошло, давайте попробуем вызвать нашу функцию вообще без аргумента:
g.good_afternoon() # Результат: # Good afternoon <__main__.Greetings object at 0x00000284083D1B88>
Что же тут происходит?
Когда мы создаем экземпляр класса, то первым аргументом, передаваемым функции, является сам этот экземпляр. Таким образом, причина, по которой мы получаем ошибку TypeError, заключается в том, что Python считывает функцию g.good_afternoon(‘John’) как g.good_afternoon(g, ‘John’). Это может показаться запутанным, но в следующих секциях будет ясно почему такое происходит.
Методы экземпляров класса
Рассмотрим новый пример класса под названием Student, который принимает в качестве параметров имя, фамилию, возраст и специальность.
class Student: def __init__(self, first, last, age, major): self.first = first self.last = last self.age = age self.major = major def profile(self): print(f"Student name {self.first + ' ' + self.last}") print(f"Student age: {self.age}") print(f"Major: {self.major}") s = Student('Sally' , 'Harris', 20, 'Biology') s.profile()
Результат:
Student name Sally Harris Student age: 20 Major: Biology
При определении методов экземпляра мы должны передавать в качестве первого аргумента ключевое слово self. Это решает проблему передачи экземпляра класса функциям в качестве первого аргумента. Давайте создадим текущий класс и добавим функциональность регистрации, чтобы показать способность методов экземпляра класса взаимодействовать с атрибутами.
class Student: def __init__(self, first, last, age, major): self.first = first self.last = last self.age = age self.major = major self.courses = [] def profile(self): print(f"Student name {self.first + ' ' + self.last}") print(f"Student age: {self.age}") print(f"Major: {self.major}") def enrol(self, course): self.courses.append(course) print(f"enrolled {self.first} in {course}") def show_courses(self): print(f"{self.first + '' + self.last} is taking the following courses") for course in self.courses: print(course) s = Student('Sally' , 'Harris', 20, 'Biology') s.enrol('Biochemistry I') # enrolled Sally in Biochemistry I s.enrol('Literature') # enrolled Sally in Literature s.enrol('Mathematics') # enrolled Sally in Mathematics s.show_courses() # SallyHarris is taking the following courses # Biochemistry I # Literature # Mathematics
Все вышеперечисленные методы были привязаны к экземпляру класса Student, который мы сохранили в переменную s. Мы можем проверить это, используя ключевое слово dir для нашего экземпляра класса, чтобы увидеть все атрибуты и методы, привязанные к нему.
dir(s) # Результат: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'courses', 'enrol', 'first', 'last', 'major', 'profile', 'show_courses']
В рамках класса мы можем сочетать функции, привязанные к экземплярам класса и обычные функции, которые мы привели в начале данной статьи. Давайте ниже добавим функцию, которая будет выводить на экран текущий учебный год.
import datetime as dt class Student: def __init__(self, first, last, age, major): self.first = first self.last = last self.age = age self.major = major self.courses = [] def profile(self): print(f"Student name {self.first + ' ' + self.last}") print(f"Student age: {self.age}") print(f"Major: {self.major}") def enrol(self, course): self.courses.append(course) print(f"enrolled {self.first} in {course}") def show_courses(self): print(f"{self.first + '' + self.last} is taking the following courses") for course in self.courses: print(course) def academic_year(): now = dt.datetime.now() s = now.year, now.year -1 print(f"Current academic year is { str(s[0]) + '/' + str(s[1]) }")
Однако мы все равно получим ошибку, если попытаемся вызвать эту новую функцию из экземпляра класса, так как вызов методов/функций из экземпляров класса всегда передает сам экземпляр класса в качестве первого аргумента. Таким образом, если мы хотим вызвать функцию academic_year(), это можно сделать это следующим образом:
Student.academic_year() # Результат: Current academic year is 2020/2019
Заключение
При вызове функции из класса используется синтаксис ClassName.FunctionName().
При вызове функции, привязанной к экземпляру класса, первым аргументом, передаваемым функции, является сам экземпляр класса. Такие функции также называют методами.
Чтобы метод правильно работал, мы должны при его написании в качестве первого аргумента указать ключевое слово self.
Данные методы дают нам возможность взаимодействовать с атрибутами, связанными с экземплярами класса.
Перевод статьи Adding Functions to Python Classes.
- 0 views
- 0 Comment