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

classmethod and staticmethod as Descriptors

Sveip for å vise menyen

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?

Velg det helt riktige svaret

Alt var klart?

Hvordan kan vi forbedre det?

Takk for tilbakemeldingene dine!

Seksjon 2. Kapittel 2

Spør AI

expand

Spør AI

ChatGPT

Spør om hva du vil, eller prøv ett av de foreslåtte spørsmålene for å starte chatten vår

Seksjon 2. Kapittel 2
some-alt