@staticmethod vs @classmethod
@staticmethod działa jak zwykła funkcja bez automatycznego argumentu, a @classmethod dostaje klasę jako cls i zwykle służy jako alternatywny konstruktor.
Porównanie w tabeli
#Pierwszy argument
- @staticmethod
- Brak
- @classmethod
cls(klasa)
Dostęp do atrybutów klasy
- @staticmethod
- Nie, chyba że przez nazwę klasy wpisaną na sztywno
- @classmethod
- Tak, przez
cls
Tworzenie obiektu przez cls(...)
- @classmethod
- Tak, to typowe zastosowanie
Zachowanie w klasie pochodnej
- @staticmethod
- Nie dotyczy, brak odniesienia do klasy
- @classmethod
clsto klasa pochodna, nie bazowa
Wywołanie
- @staticmethod
Klasa.metoda(args)- @classmethod
Klasa.metoda(args)
Typowe użycie
- @staticmethod
- Walidacja, przeliczenia niezależne od danych obiektu
- @classmethod
- Alternatywne konstruktory (from_text, from_dict)
Przykład
#class Grade:
def __init__(self, points):
self.points = points
@staticmethod
def is_valid(points):
return 0 <= points <= 100
@classmethod
def from_percent(cls, percent, maximum):
return cls(round(percent / 100 * maximum))
print(Grade.is_valid(120))
grade = Grade.from_percent(75, 80)
print(grade.points)Definicja i zastosowanie
#Oba dekoratory definiują metodę, którą wywołasz przez nazwę klasy, bez tworzenia obiektu. Żadna z nich nie dostaje self, więc nie ma dostępu do danych konkretnego obiektu.
Różnią się pierwszym argumentem. Metoda statyczna nie dostaje nic automatycznie: to zwykła funkcja, tylko umieszczona wewnątrz klasy dla porządku. Metoda klasy dostaje jako pierwszy argument samą klasę (cls), dzięki czemu może odwołać się do jej atrybutów i, co ważniejsze, utworzyć obiekt przez cls(...). W klasie pochodnej cls wskazuje na tę klasę pochodną, a nie na klasę, w której metodę zapisano.
Użyj @staticmethod dla funkcji pomocniczej, która logicznie należy do klasy, np. walidacji albo przeliczenia, ale nie potrzebuje ani obiektu, ani klasy. Użyj @classmethod, gdy metoda ma tworzyć obiekty z danych w innym formacie niż zwykły konstruktor, np. from_text() albo from_dict(), albo gdy potrzebuje dostępu do atrybutów klasy, takich jak wspólny licznik.
Składnia
#class Nazwa:
@staticmethod
def metoda(arg):
...
@classmethod
def inna(cls, arg):
return cls(arg)Więcej przykładów
#class Task:
def __init__(self, number):
self.number = number
@classmethod
def from_code(cls, code):
return cls(code.removeprefix("zadanie_"))
class Quiz(Task):
pass
task = Quiz.from_code("zadanie_7_3")
print(type(task).__name__, task.number)class Course:
count = 0
def __init__(self, title):
self.title = title
Course.count += 1
@staticmethod
def slugify(title):
return title.lower().replace(" ", "-")
python_course = Course("Python od zera")
print(Course.slugify(python_course.title))
print(Course.count)Dobre praktyki
#- Jeśli metoda nie używa ani
self, anicls, prawdopodobnie powinna być statyczna albo w ogóle poza klasą. - Nazywaj alternatywne konstruktory z przedrostkiem
from_, np.from_json(),from_row(). To konwencja znana z biblioteki standardowej. - W metodzie klasy twórz obiekty przez
cls(...), a nie przez nazwę klasy wpisaną na sztywno, żeby działała poprawnie też w klasach pochodnych.
Powiązane hasła
#- @staticmethodMetoda, która nie dostaje automatycznie ani obiektu, ani klasy. Działa jak zwykła funkcja umieszczona w klasie.
- @classmethodMetoda, która zamiast obiektu dostaje klasę (cls). Najczęściej służy jako alternatywny konstruktor.
- selfPierwszy parametr metody: obiekt, na którym metodę wywołano. Daje dostęp do jego atrybutów i innych metod.
- classDefiniuje klasę: szablon obiektów łączący dane i funkcje, które na nich działają.
- DekoratoryFunkcje, które opakowują inne funkcje i dodają im zachowanie, np. logowanie lub sprawdzanie uprawnień. Zapis @nazwa.
Widzisz błąd albo brakuje przykładu? Napisz do nas.