Разбираемся с методами объектов в Python
Основные типы методов в Python
Метод в Python - это функция, определенная внутри класса и предназначенная для работы с объектами этого класса. Самый распространенный тип - метод экземпляра. Он первым аргументом принимает self - ссылку на текущий экземпляр.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"Меня зовут {self.name}, мне {self.age} лет."
p = Person("Анна", 25)
print(p.introduce())атрибуты класса python (атрибуты классов и объектов в python)
Меня зовут Анна, мне 25 лет.
библиотека классов python (библиотека классов в python)
Забыв указать self, программист получит ошибку при вызове метода. Это наиболее частая проблема.
Если метод объявлен без self, Python попытается передать экземпляр как первый позиционный аргумент, что приведет к несоответствию количества аргументов.
class Person:
def introduce(): # self отсутствует
return "Ошибка"
p = Person()
p.introduce() # TypeError: introduce() takes 0 positional arguments but 1 was given
метод объекта python (методы объектов в python)
Как сделать метод, который принадлежит классу, а не экземпляру?
Декоратор @classmethod превращает обычный метод в метод класса. Первый параметр - cls (сам класс). Такие методы часто используют как альтернативные конструкторы.
class User:
def __init__(self, username, email):
self.username = username
self.email = email
@classmethod
def from_email(cls, email):
name = email.split('@')[0]
return cls(name, email)
u = User.from_email("ivan@example.com")
print(u.username) # ivanметод call python (метод __call__ в python)
ivan
Python структура объекта (структура объекта в python)
Распространенная ошибка - забыть декоратор или использовать self вместо cls. В первом случае метод станет экземплярным и будет требовать self, во втором - логика работы с классом нарушится.
Когда нужен метод, не зависящий ни от экземпляра, ни от класса?
Статический метод, помеченный @staticmethod, - это обычная функция внутри класса. Он не принимает ни self, ни cls. Используется для группировки вспомогательных функций, имеющих отношение к классу.
class MathUtils:
@staticmethod
def is_even(n):
return n % 2 == 0
print(MathUtils.is_even(4)) # TruePython создание объектов (создание объектов в python)
True
Self object python (объект self в python)
Ошибка - пытаться обратиться к атрибутам экземпляра или класса внутри статического метода. Это невозможно, так как статический метод не имеет ссылок на объекты. Для работы с атрибутами класса используйте @classmethod.
Как вычислить значение атрибута динамически и контролировать его изменение?
Декоратор @property позволяет создать свойство - метод, вызываемый как атрибут. Свойство может иметь геттер, сеттер и делитер. Это дает возможность добавлять логику при доступе к атрибуту, не меняя интерфейс.
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def area(self):
return 3.14 * self._radius ** 2
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("Радиус должен быть положительным")
self._radius = value
c = Circle(5)
print(c.area) # 78.5
c.radius = 10
print(c.area) # 314.0
# c.radius = -1 # ValueErrorObject attribute python (атрибуты объекта в python)
78.5 314.0
Python call method (вызов метода в python)
Частая ошибка - определить сеттер без геттера. Если геттер уже существует с тем же именем, сеттер добавляется с помощью @имя.setter. Если же геттер не объявлен, Python не даст использовать сеттер. Также нельзя использовать свойство с тем же именем, что и атрибут (например, self.radius вместо self._radius), иначе возникнет рекурсия.
Как переопределить стандартное поведение объектов?
Специальные (магические) методы, окруженные двойными подчеркиваниями, позволяют классу взаимодействовать с встроенными операциями Python. Самые популярные: __init__ (конструктор), __str__ (строковое представление), __add__ (сложение), __repr__ (представление для разработчика).
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
if not isinstance(other, Vector):
return NotImplemented
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other):
if not isinstance(other, Vector):
return False
return self.x == other.x and self.y == other.y
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3) # Vector(4, 6)
print(v1 == v2) # FalsePython класс данных (класс данных в python)
Vector(4, 6) False
Ошибка - забыть возвращать NotImplemented для неподдерживаемых типов в __add__. Если возвращается NotImplemented, Python пытается обработать операцию у второго операнда. Возврат False может привести к некорректному поведению.
Расширенные примеры методов
Класс с комбинацией различных методов
class Employee:
company = "TechCorp"
def __init__(self, name, salary, department):
self.name = name
self.salary = salary
self.department = department
@property
def annual_bonus(self):
return self.salary * 0.1
@classmethod
def from_dict(cls, data):
return cls(data['name'], data['salary'], data['department'])
@staticmethod
def is_salary_valid(salary):
return salary > 0
def __repr__(self):
return f"Employee({self.name}, {self.department})"
def __eq__(self, other):
if not isinstance(other, Employee):
return NotImplemented
return self.name == other.name and self.department == other.department
data = {'name': 'Иван', 'salary': 50000, 'department': 'IT'}
emp1 = Employee.from_dict(data)
print(emp1)
print(emp1.annual_bonus)
print(Employee.is_salary_valid(emp1.salary))
emp2 = Employee.from_dict(data)
print(emp1 == emp2)
Employee(Иван, IT) 5000.0 True True
Использование свойства для вычисления возраста
class Person:
def __init__(self, name, birth_year):
self.name = name
self._birth_year = birth_year
@property
def age(self):
from datetime import datetime
return datetime.now().year - self._birth_year
@age.setter
def age(self, new_age):
if new_age < 0 or new_age > 150:
raise ValueError("Некорректный возраст")
from datetime import datetime
self._birth_year = datetime.now().year - new_age
p = Person("Ольга", 1990)
print(p.age)
p.age = 20
print(p._birth_year)
34 2004
Метод класса как фабрика: создание объектов из строки
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def from_polar(cls, radius, angle):
import math
x = radius * math.cos(angle)
y = radius * math.sin(angle)
return cls(x, y)
def __repr__(self):
return f"Point({self.x:.2f}, {self.y:.2f})"
p = Point.from_polar(10, math.pi/4)
print(p)
Point(7.07, 7.07)
Статический метод для проверки данных
class StringUtils:
@staticmethod
def is_palindrome(s):
s = ''.join(c.lower() for c in s if c.isalnum())
return s == s[::-1]
print(StringUtils.is_palindrome("А роза упала на лапу Азора"))
True
Магический метод __call__ для функторов
class Adder:
def __init__(self, step):
self.step = step
def __call__(self, x):
return x + self.step
add_five = Adder(5)
print(add_five(10))
15