Classes often need configured variants of a method or type-based dispatch on an argument.
Plain partial and singledispatch don't understand methods: they don't bind self. functools provides method-aware versions.
partialmethod creates a method with some arguments pre-filled; self is bound normally:
class Light:
def set_state(self, on): ...
turn_on = partialmethod(set_state, True)Assigning a plain partial object as a class attribute does not bind self today, so obj.attr() calls the function without the instance. In 3.13 this raises a FutureWarning, because partial will become a method descriptor in a future release. Use partialmethod for methods, or wrap the partial in staticmethod to keep the non-binding behaviour explicitly.
singledispatchmethod dispatches on the type of the first argument after self (or cls):
class Formatter:
@singledispatchmethod
def format(self, value): ...
@format.register
def _(self, value: int): ...It also works with @classmethod when stacked correctly: @singledispatchmethod on the outside, @classmethod on the inside, both for the base and for registered implementations.
These descriptors return bound callables on attribute access, so introspection and help() work as for ordinary methods.
Example
import warnings
from functools import partial, partialmethod, singledispatchmethod
class Light:
on = False
def set_state(self, on): self.on = on
turn_on = partialmethod(set_state, True)
light = Light(); light.turn_on(); print(light.on) # True
class Formatter:
@singledispatchmethod
def format(self, value):
return str(value)
@format.register
def _(self, value: float):
return f"{value:.2f}"
@format.register
def _(self, value: list):
return "[" + "; ".join(self.format(v) for v in value) + "]"
print(Formatter().format([1, 2.5, "x"])) # [1; 2.50; x]
class Bad:
hello = partial(print, "hi") # not bound to instances
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
Bad().hello # attribute access warns in 3.13
print(caught[0].category.__name__) # FutureWarningRemember
partialmethodpre-fills arguments and binds self like a normal method- A plain
partialclass attribute doesn't bind self and warns in 3.13 singledispatchmethoddispatches on the first argument after self
Watch out for
- Assigning
partial(...)as a class attribute and expecting it to receive self.