Source code for pyiron_workflow.overloading

import functools


[docs] def overloaded_classmethod(class_method): """ Decorator to define a method that behaves like both a classmethod and an instancemethod under the same name. Args: instance_method: A method defined on the same object as the decorated method, to be used when an instance of the object calls the decorated method ( instead of a class call) Returns ------- descriptor A descriptor that dispatches to the classmethod when accessed via the class, and to the given instance method when accessed via an instance. Examples: >>> class Foo: ... def __init__(self, y): ... self.y = y ... ... @classmethod ... def _doit_classmethod(cls, x): ... return f"Class {cls.__name__} doing {x}" ... ... @overloaded_classmethod(class_method=_doit_classmethod) ... def doit(self, x): ... return f"Instance of type {type(self).__name__} doing {x} + {self.y}" ... >>> Foo.doit(10) 'Class Foo doing 10' >>> Foo(5).doit(20) 'Instance of type Foo doing 20 + 5' """ class Overloaded: def __init__(self, f_instance, f_class): self.f_instance = f_instance self.f_class = f_class functools.update_wrapper(self, f_instance) def __get__(self, obj, cls): if obj is None: f_class = ( cls.__dict__[self.f_class] if isinstance(self.f_class, str) else self.f_class ) if isinstance(f_class, classmethod): f_class = f_class.__func__ @functools.wraps(self.f_class) def bound(*args, **kwargs): return f_class(cls, *args, **kwargs) return bound else: @functools.wraps(self.f_instance) def bound(*args, **kwargs): return self.f_instance(obj, *args, **kwargs) return bound def wrapper(f_instance): return Overloaded(f_instance, class_method) return wrapper