For your specific example, you can write
def round_sqrt(x):
return round(sqrt(x))
Alex's answer generalizes this; he defines a function that creates round_sqrt
for you. If the function is already defined, you just pass it as an argument to rounder
:
round_sqrt = rounder(sqrt)
Of course, you don't need to define round_sqrt
if you don't want to. rounder(sqrt)(3.2)
can be called directly, although it's far more efficient to safe the return value of rounder
if you expect to use it multiple times, rather than redefining it each time.
Otherwise, the decorator syntax is just short for (using Alex's example)
def adder(x, y):
return x + y
adder = rounder(adder)
As I said in my comment, this is an example of implementing composition. Mathematically, composition is simple, because mathematical functions always take a single argument and return a single argument. As such, the composition of two functions f
and g
could always be defined simply as
def compose(f, g):
def h(x): # The name doesn't matter
return f(g(x))
return h
Then
round_sqrt = compose(round, sqrt)
(Ignoring all sorts of practical concerns around the implementation, Python could in theory even provide a Unicode operator ∘
for functions: round_sqrt = round ∘ sort
. Explaining why this won't happen is beyond the scope of this answer.)
In Python, though, functions are far more complicated. They can take multiple arguments, they can accept arbitrary numbers of arguments and arbitrary keyword arguments, and while each technically returns a single value, that value can be a tuple which is thought of as multiple values or a dict
. As a result, there may be many ways you might expect to pass the return value of g
to a function f
, more than can easily be accommodated in a simple compose
function.