Suppose we have a function that returns the boiling point of water in celsius:
def boiling_point(): return 100 print boiling_point() # returns 100
Suppose we are now at high altitude and the boiling point is now 97 degree. We can wrap the function like this:
def calibrate(f): def g(): return f() - 3 return g def boiling_point(): return 100 print boiling_point() # returns 100 boiling_point_calibrated = calibrate(boiling_point) print boiling_point_calibrated() # returns 97
In fact, we can do better. We can assign the calibrated function back to the original function name. As a result, nothing is changed on the calling side:
def calibrate(f): def g(): return f() - 3 return g def boiling_point(): return 100 print boiling_point() # return 100 boiling_point = calibrate(boiling_point) print boiling_point() # returns 97
When used in this way, the function calibrate() is called a decorator, and there is a shortcut for it:
def calibrate(f): def g(): return f() - 3 return g @calibrate def boiling_point(): return 100 print boiling_point() # returns 97
Even better is for the offset to be configurable. The boiling point is dependent on the altitude after all. What we can do is to create a function which returns a function that decorates a function:
def calibrate_offset(offset): def calibrate(f): def g(): return f() - offset return g return calibrate @calibrate_offset(3) def boiling_point(): return 100 print boiling_point() # returns 97
Finally we can generalize the original function by adding *args and **kwargs to it:
def calibrate_offset(offset): def calibrate(f): def g(*args, **kwargs): return f(*args, **kwargs) - offset return g return calibrate @calibrate_offset(3) def boiling_point(): return 100 print boiling_point() # returns 97
Lastly, decorator can be nested. What do you think x will be in the following case?
def calibrate_offset(offset): def calibrate(f): def g(*args, **kwargs): return f(*args, **kwargs) - offset return g return calibrate @calibrate_offset(3) @calibrate_offset(4) def boiling_point(): return 100 x = boiling_point()
No comments:
Post a Comment