When I initially saw patch_to in the 01_core notebook, it seems super daunting and I didn’t understand what it was doing so I decided to write a post to say what it is doing and hopefully have others that understand it better, correct me if I misunderstand any of it.
Here is the code we will be breaking down in this post:
#export
def patch_to(cls, as_prop=False):
"Decorator: add `f` to `cls`"
def _inner(f):
nf = copy(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"{cls.__name__}.{f.__name__}"
setattr(cls, f.__name__, property(nf) if as_prop else nf)
return f
return _inner
This creates what is called a decorator. It can be referred to using an @ and will run code before and after the function it is decorating runs.
The purpose of patch_to is to take a class and add a new function to the class. So to use it, first identify what class you want to add a function to. Then, pass that class to the decorator and put a function directly below the decorator like so:
@patch_to(_T3)
def func1(self,x): return x+2
Now, remember a decorator runs on the code that follows it and it has the ability to process code before and after the code
So to orient ourselves with the actual code, _T3 now is cls in the code from 01_core and the function func1 is f.
So first, a copy of func1 (f) is created called nf.
Next, the variable WRAPPER_ASSIGNEMENTS from the library functools is iterated through.
This is what WRAPPER ASSIGNEMNTS contains:
('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')
So each of these is going to be put into o and looped through setattr
.
This is copying all of the attributes from f using getattr(f,o) and putting them in the copy of f, nf.
Then, __qualname__
is updated to be {class.__name__
}.{function.__name__
} in this case: _T3.func1
Lastly, this function is added to the class using setattr. If as_prop is set to True, a property function wraps nf, otherwise, it is passed directly.
I think I finally have a decent idea how decorators work and especially how this specific decorator works to add a function to a class.
I’m hoping that by sharing my thought process going through this, somebody else will gain a deeper understanding of this code and also I will get feedback on any issue I may have had in my explanation.