There’s a ton of useful stuff in fastcore, so I’d consider using it! But if you really just want to use patching it’s actually a very nice and slim implementation with only two built-in dependencies:
import functools
from types import FunctionType
def copy_func(f):
"Copy a non-builtin function (NB `copy.copy` does not work for this)"
if not isinstance(f,FunctionType): return copy(f)
fn = FunctionType(f.__code__, f.__globals__, f.__name__, f.__defaults__, f.__closure__)
fn.__dict__.update(f.__dict__)
return fn
def patch_to(cls, as_prop=False):
"Decorator: add `f` to `cls`"
if not isinstance(cls, (tuple,list)): cls=(cls,)
def _inner(f):
for c_ in cls:
nf = copy_func(f)
# `functools.update_wrapper` when passing patched function to `Pipeline`, so we do it manually
for o in functools.WRAPPER_ASSIGNMENTS: setattr(nf, o, getattr(f,o))
nf.__qualname__ = f"{c_.__name__}.{f.__name__}"
setattr(c_, f.__name__, property(nf) if as_prop else nf)
return f
return _inner
def patch(f):
"Decorator: add `f` to the first parameter's class (based on f's type annotations)"
cls = next(iter(f.__annotations__.values()))
return patch_to(cls)(f)
That’s the only code needed:
class MyClass():
def __init__(self):
pass
@patch
def new_fun(self:MyClass):
print("I'm a patched function!")
MyInstance = MyClass()
MyInstance.new_fun()
"I'm a patched function!"
EDIT: Oh I forgot to mention that fastcore itself is extremely low weight: The only external library used is numpy (and dataclasses if your python is < 3.7).