← Назад к вопросам

Какие аргументы принимает метод @staticmethod?

1.8 Middle🔥 131 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Аргументы метода @staticmethod в Python

Метод, украшенный @staticmethod, не получает автоматически никаких аргументов (ни self, ни cls). Он принимает только те аргументы, которые явно передаёт вызывающий код.

1. Основное отличие от обычных методов

class Calculator:
    
    # Обычный метод (instance method)
    def add(self, a, b):
        # self - автоматический аргумент
        return a + b
    
    # Метод класса
    @classmethod
    def create_from_string(cls, string_repr):
        # cls - автоматический аргумент
        return cls()
    
    # Статический метод
    @staticmethod
    def multiply(a, b):
        # БЕЗ self, БЕЗ cls
        return a * b

# Вызовы
calc = Calculator()

# Обычный метод - передаём только (a, b)
calc.add(5, 3)                    # OK: self передаётся автоматически

# Метод класса - передаём то же, что объявили
Calculator.create_from_string("5") # OK: cls передаётся автоматически

# Статический метод - передаём ровно то, что объявили
Calculator.multiply(5, 3)          # OK: аргумента нет
Calculator.multiply(5, 3, "extra") # ERROR: неожиданный аргумент

2. Сигнатура @staticmethod

class Example:
    # Без аргументов
    @staticmethod
    def no_args():
        return "No arguments"
    
    # С позиционными аргументами
    @staticmethod
    def with_args(a, b, c):
        return a + b + c
    
    # С именованными аргументами
    @staticmethod
    def with_kwargs(name, age=None, city=None):
        return f"{name}, {age}, {city}"
    
    # С *args и **kwargs
    @staticmethod
    def with_all_args(*args, **kwargs):
        return args, kwargs

# Вызовы
Example.no_args()                      # OK
Example.with_args(1, 2, 3)            # OK: 3
Example.with_kwargs("John", age=30)   # OK
Example.with_all_args(1, 2, x=3, y=4) # OK: ((1, 2), {'x': 3, 'y': 4})

3. Важное: нельзя передавать self или cls

class MyClass:
    @staticmethod
    def static_method(self, a):  # ❌ ОШИБКА в декларации
        return a
    
    # Python будет воспринимать self как обычный параметр!

# Вызов будет требовать обоих аргументов
MyClass.static_method("first_arg", "second_arg")  # OK

# Но это не рекомендуется, так как нарушает конвенцию

4. Сравнение трёх типов методов

class Demo:
    class_variable = "I am class variable"
    
    # INSTANCE METHOD
    def instance_method(self, x):
        print(f"self: {self}")
        print(f"x: {x}")
        print(f"class_variable: {self.class_variable}")
    
    # CLASS METHOD
    @classmethod
    def class_method(cls, x):
        print(f"cls: {cls}")
        print(f"x: {x}")
        print(f"class_variable: {cls.class_variable}")
    
    # STATIC METHOD
    @staticmethod
    def static_method(x):
        print(f"x: {x}")
        # Нет доступа к self или cls!
        # print(f"class_variable: {class_variable}")  # NameError!

# Вызовы и сигнатуры
obj = Demo()

# instance_method(self, x) -> вызываем с (x)
obj.instance_method("value")       # self = obj
Demo.instance_method(obj, "value") # явная передача self

# class_method(cls, x) -> вызываем с (x)
obj.class_method("value")          # cls = Demo
Demo.class_method("value")         # cls = Demo (то же самое)

# static_method(x) -> вызываем с (x)
obj.static_method("value")         # просто функция
Demo.static_method("value")        # просто функция

5. Практические примеры использования

import math
from datetime import datetime
from typing import List

class MathUtils:
    """Утилиты для математических операций"""
    
    @staticmethod
    def distance(x1: float, y1: float, x2: float, y2: float) -> float:
        """Евклидово расстояние между двумя точками"""
        return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
    
    @staticmethod
    def gcd(a: int, b: int) -> int:
        """НОД двух чисел"""
        while b:
            a, b = b, a % b
        return a
    
    @staticmethod
    def is_prime(n: int) -> bool:
        """Проверка простоты числа"""
        if n < 2:
            return False
        for i in range(2, int(math.sqrt(n)) + 1):
            if n % i == 0:
                return False
        return True

class DateUtils:
    """Утилиты для работы с датами"""
    
    @staticmethod
    def days_between(date1: datetime, date2: datetime) -> int:
        """Количество дней между двумя датами"""
        return abs((date2 - date1).days)
    
    @staticmethod
    def is_leap_year(year: int) -> bool:
        """Проверка високосного года"""
        return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

# Использование
print(MathUtils.distance(0, 0, 3, 4))  # 5.0
print(MathUtils.gcd(48, 18))           # 6
print(MathUtils.is_prime(17))          # True
print(DateUtils.is_leap_year(2024))    # True

6. Когда использовать @staticmethod

# ✓ ИСПОЛЬЗУЙ @staticmethod когда:

# 1. Утилиты, которые не зависят от состояния класса/инстанса
@staticmethod
def format_currency(amount: float, currency: str = "USD") -> str:
    return f"{currency} {amount:.2f}"

# 2. Вспомогательные функции
@staticmethod
def validate_email(email: str) -> bool:
    import re
    pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
    return re.match(pattern, email) is not None

# 3. Функции, логически принадлежащие классу
class FileHandler:
    @staticmethod
    def read_file(path: str) -> str:
        with open(path, 'r') as f:
            return f.read()
    
    @staticmethod
    def write_file(path: str, content: str) -> None:
        with open(path, 'w') as f:
            f.write(content)

# ✗ НЕ ИСПОЛЬЗУЙ @staticmethod когда:

# 1. Нужен доступ к состоянию инстанса
class User:
    def __init__(self, name):
        self.name = name
    
    # ❌ НЕПРАВИЛЬНО - нужен self
    @staticmethod
    def greet(greeting="Hello"):
        return f"{greeting}, {self.name}"  # NameError!
    
    # ✓ ПРАВИЛЬНО
    def greet(self, greeting="Hello"):
        return f"{greeting}, {self.name}"

# 2. Нужна логика создания инстанса
class Person:
    # ✗ НЕПРАВИЛЬНО - используй @classmethod
    @staticmethod
    def from_string(data: str):
        name, age = data.split(',')
        return Person(name, int(age))  # NameError: Person не определён?
    
    # ✓ ПРАВИЛЬНО
    @classmethod
    def from_string(cls, data: str):
        name, age = data.split(',')
        return cls(name, int(age))  # используем cls

7. Декоратор @staticmethod внутри

# @staticmethod возвращает дескриптор
class MyDescriptor:
    def __init__(self, func):
        self.func = func
    
    def __get__(self, obj, objtype=None):
        # Просто возвращаем функцию как есть
        return self.func

# Упрощённо, @staticmethod работает примерно так
class Example:
    @staticmethod
    def my_static(x):
        return x * 2

# Эквивалентно
class Example2:
    def my_static(x):
        return x * 2
    my_static = staticmethod(my_static)

# Обе работают одинаково
print(Example.my_static(5))   # 10
print(Example2.my_static(5))  # 10

Резюме

Аспектinstance@classmethod@staticmethod
Первый аргументselfclsнет
Может вызвать на объекте
Может вызвать на классе
Доступ к self
Доступ к cls
Создание инстансов
Утилиты/хелперы

Главное: @staticmethod не получает автоматических аргументов и работает как обычная функция, логически объединённая с классом.