Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen classmethod and staticmethod as Descriptors | Descriptors in the Wild
Python Descriptors Explained

classmethod and staticmethod as Descriptors

Swipe um das Menü anzuzeigen

classmethod and staticmethod are built-in descriptors. They use __get__ to change what gets passed as the first argument when a method is called. Understanding them as descriptors explains exactly how they work – and why they behave differently from regular methods.

Regular Methods Are Non-Data Descriptors

Before looking at classmethod and staticmethod, it helps to know that regular functions stored as class attributes are themselves non-data descriptors. Their __get__ binds the instance as the first argument:

1234567891011
# A regular function's __get__ binds the instance class Report: def generate(self): return f"Report from {self}" print(type(Report.__dict__["generate"])) # <class 'function'> print(hasattr(Report.__dict__["generate"], "__get__")) # True report = Report() bound_method = Report.__dict__["generate"].__get__(report, Report) print(bound_method()) # Same as report.generate()

classmethod — Binding the Class

classmethod wraps a function so that __get__ binds the class as the first argument instead of the instance. This happens whether the method is called on an instance or on the class directly:

123456789101112131415161718192021222324
# classmethod binds the class, not the instance class Transaction: _currency = "USD" def __init__(self, transaction_id, amount): self.transaction_id = transaction_id self.amount = amount @classmethod def get_currency(cls): return cls._currency @classmethod def from_string(cls, raw_string): # Parsing "TX-001:4500.0" into a Transaction transaction_id, amount = raw_string.split(":") return cls(transaction_id, float(amount)) # Calling on the class and on an instance – both receive the class print(Transaction.get_currency()) # "USD" transaction = Transaction.from_string("TX-001:4500.0") print(transaction.transaction_id) # "TX-001" print(transaction.amount) # 4500.0

How classmethod.__get__ Works

1234567891011121314
# Inspecting classmethod as a descriptor class Config: debug = False @classmethod def is_debug(cls): return cls.debug print(type(Config.__dict__["is_debug"])) # <class 'classmethod'> print(hasattr(Config.__dict__["is_debug"], "__get__")) # True # __get__ returns a bound method with the class pre-filled bound = Config.__dict__["is_debug"].__get__(None, Config) print(bound()) # False – same as Config.is_debug()

staticmethod — No Binding at All

staticmethod wraps a function so that __get__ returns the original function unchanged – no instance, no class is bound. It behaves like a plain function that happens to live in a class namespace:

123456789101112131415
# staticmethod – no binding, just a plain function in class scope class CurrencyConverter: _rate = 1.08 # EUR to USD @staticmethod def format_amount(amount, symbol): return f"{symbol}{amount:,.2f}" @classmethod def convert_to_usd(cls, eur_amount): usd_amount = eur_amount * cls._rate return cls.format_amount(usd_amount, "$") print(CurrencyConverter.format_amount(4500.0, "€")) # €4,500.00 print(CurrencyConverter.convert_to_usd(4500.0)) # $4,860.00

classmethod vs staticmethod

question mark

What does classmethod.__get__ pass as the first argument when the method is called?

Wählen Sie die richtige Antwort aus

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 2. Kapitel 2

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

Abschnitt 2. Kapitel 2
some-alt