Методы в языке Python: полное руководство
Определение методов в Python
Основным способом определения метода экземпляра является использование параметра self в качестве первого аргумента. Это позволяет методу получать доступ к данным конкретного объекта и изменять их.
class MyClass:
def __init__(self, value):
self.value = value
def show_value(self):
print(f"Значение: {self.value}")
obj = MyClass(42)
obj.show_value() # Вывод: Значение: 42атрибуты класса python (атрибуты классов и объектов в python)
Значение: 42
библиотека классов python (библиотека классов в python)
Параметр self автоматически передается при вызове метода через экземпляр. Важно не забывать указывать его в определении, иначе возникнет ошибка при вызове.
Как определить метод без доступа к экземпляру, используя только класс?
Для методов, которые работают с атрибутами класса, а не экземпляра, применяется декоратор @classmethod. Первый аргумент такого метода - cls (ссылка на класс).
class MyClass:
class_attribute = 0
@classmethod
def increment_class_attr(cls):
cls.class_attribute += 1
return cls.class_attribute
print(MyClass.increment_class_attr()) # 1
print(MyClass.increment_class_attr()) # 2метод объекта python (методы объектов в python)
1 2
Python структура объекта (структура объекта в python)
Важно:
Методы класса могут быть вызваны как от класса, так и от экземпляра, но при вызове от экземпляра все равно первым аргументом будет класс.Как создать вспомогательную функцию внутри класса, не зависящую от объекта?
Для функций, которые логически принадлежат классу, но не требуют доступа ни к экземпляру, ни к классу, используется декоратор @staticmethod. Они ведут себя как обычные функции, но размещены в пространстве имен класса.
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def multiply(a, b):
return a * b
print(MathUtils.add(5, 3)) # 8
print(MathUtils.multiply(4, 2)) # 8Python создание объектов (создание объектов в python)
8 8
Self object python (объект self в python)
Как сделать метод, который ведет себя как атрибут (геттер/сеттер)?
Декоратор @property позволяет определить метод, который вызывается при обращении к атрибуту без круглых скобок. Для записи значения используются сеттеры с @attribute.setter, для удаления - @attribute.deleter.
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32
@fahrenheit.setter
def fahrenheit(self, value):
self._celsius = (value - 32) * 5/9
t = Temperature(0)
print(t.fahrenheit) # 32.0
t.fahrenheit = 100
print(t._celsius) # 37.7777...Object attribute python (атрибуты объекта в python)
32.0 37.77777777777778
Python call method (вызов метода в python)
Как определить абстрактный метод, который должен быть переопределен в подклассах?
Используя модуль abc и декоратор @abstractmethod, можно создавать абстрактные базовые классы. Такие методы не имеют реализации в базовом классе и обязаны быть переопределены в производных классах.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def sound(self):
pass
class Dog(Animal):
def sound(self):
return "Woof"
# animal = Animal() - ошибка
dog = Dog()
print(dog.sound()) # WoofPython класс данных (класс данных в python)
Woof
Class method python (методы классов в python)
Как определить специальные методы для перегрузки операторов?
Методы с двойными подчеркиваниями (dunder) позволяют объектам поддерживать встроенные операции. Например, __add__ для сложения, __len__ для длины.
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3) # Vector(4, 6)Python object methods (методы объектов в python)
Vector(4, 6)
Типичные ошибки и их решение
- Забыли
self: При определении метода экземпляра безselfвызов приведет к ошибкеTypeError: method() takes 0 positional arguments but 1 was given. Решение - всегда добавлятьselfпервым параметром. - Перепутали
selfиcls: В методах класса вместоselfиспользуетсяcls. Если в@classmethodнаписатьself, работать будет, но это введет в заблуждение. Лучше придерживаться соглашения. - Вызов метода класса через экземпляр: Хотя это работает, лучше вызывать метод класса от имени класса, чтобы подчеркнуть его природу.
- Не использовать
@propertyдля геттеров: Если метод не требует аргументов и просто возвращает вычисленное значение, лучше использовать свойство, а не обычный метод. - Ошибка при определении абстрактного метода без наследования от
ABC: Декоратор@abstractmethodработает только внутри класса, наследующего отABC. Иначе абстрактность не будет принудительно проверяться.
# Пример 1: Метод с переменным числом аргументов
class Calculator:
def add(self, *args):
return sum(args)
calc = Calculator()
print(calc.add(1,2,3,4)) # 10
10
# Пример 2: Fluent interface - метод возвращает self
class Builder:
def __init__(self):
self.result = []
def add_item(self, item):
self.result.append(item)
return self
def build(self):
return self.result
b = Builder().add_item(1).add_item(2).add_item(3).build()
print(b) # [1,2,3]
[1, 2, 3]
# Пример 3: Метод, используемый как декоратор (callable class)
class CountCalls:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"Вызов {self.calls}: {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello!")
say_hello() # Вызов 1: say_hello / Hello!
say_hello() # Вызов 2: say_hello / Hello!
Вызов 1: say_hello Hello! Вызов 2: say_hello Hello!
# Пример 4: Методы с аннотациями типов и проверкой
class Point:
def __init__(self, x: float, y: float) -> None:
self.x = x
self.y = y
def distance_to(self, other: 'Point') -> float:
import math
return math.hypot(self.x - other.x, self.y - other.y)
p1 = Point(0,0)
p2 = Point(3,4)
print(p1.distance_to(p2)) # 5.0
5.0
# Пример 5: Дескрипторы с методами __get__, __set__, __delete__
class ValidatedAttribute:
def __init__(self, validator):
self.validator = validator
self.data = {}
def __get__(self, obj, objtype):
if obj is None:
return self
return self.data.get(id(obj), None)
def __set__(self, obj, value):
if self.validator(value):
self.data[id(obj)] = value
else:
raise ValueError(f"Некорректное значение: {value}")
class Person:
age = ValidatedAttribute(lambda v: 0 <= v <= 150)
def __init__(self, name, age):
self.name = name
self.age = age # вызовет сеттер
p = Person("Alice", 30)
print(p.age) # 30
# p.age = 200 # ValueError
30
# Пример 6: Итератор с методами __iter__ и __next__
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current < 0:
raise StopIteration
value = self.current
self.current -= 1
return value
for num in CountDown(5):
print(num, end=' ') # 5 4 3 2 1 0
5 4 3 2 1 0
# Пример 7: Контекстный менеджер с методами __enter__ и __exit__
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with FileManager('test.txt', 'w') as f:
f.write('Hello')
# после with файл закрыт
(файл test.txt создан, содержимое "Hello")
# Пример 8: Метод __call__ для создания функционального объекта
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
double = Multiplier(2)
print(double(5)) # 10
triple = Multiplier(3)
print(triple(5)) # 15
10 15