I recently studied how decorators work in python, and found an example which integrates decorators with nested functions. The code is here :
def integer_check(method):
def inner(ref):
if not isinstance(ref._val1, int) or not isinstance(ref._val2, int):
raise TypeError('val1 and val2 must be integers')
else:
return method(ref)
return inner
class NumericalOps(object):
def __init__(self, val1, val2):
self._val1 = val1
self._val2 = val2
@integer_check
def multiply_together(self):
return self._val1 * self._val2
def power(self, exponent):
return self.multiply_together() ** exponent
y = NumericalOps(1, 2)
print(y.multiply_together())
print(y.power(3))
My question is how the inner function argument("ref") accesses the instance attributes (ref._val1 and ref._val2)? It seems like ref equals the instance but i have no idea how it happenes.
well one explanation I found some time ago about the self
argument was that this:
y.multiply_together()
is roughly the same as
NumericalOps.multiply_together(y)
So now that you use that decorator it returns the function inner
which requires the ref
argument so I see that roughly happen like this (on a lower level):
NumericalOps.inner(y)
Because inner
"substitutes" multiply_together
while also adding the extra functionality
Let's first recall how a decorator works:
Decorating the method multiply_together
with the decorator @integer_check
is equivalent to adding the line: multiply_together = integer_check(multiply_together)
, and by the definition of multiply_together
, this is equivalent to multiply_together = inner
.
Now, when you call the method multiply_together
, since this is an instance method, Python implicitly adds the class instance used to invoke the method as its first (an only, in this case) argument. But multiply_togethet
is, actually, inner
, so, in fact, inner
is invoked with the class instance as an argument. This instance is mapped to the parameter ref
, and through this parameter the function gets access to the required instance attributes.
inner
replaces the original function as the value of the class attribute.
@integer_check
def multiply_together(self):
return self._val1 * self._val2
# def multiply_together(self):
# ...
#
# multiply_together = integer_check(multiply_together)
first defines a function and binds it to the name multiply_together
. That function is then passed as the argument to integer_check
, and then the return value of integer_check
is bound to the name multiply_together
. The original function is now only refernced by the name ref
that is local to inner
/ multiply_together
.
The definition of inner
implies that integer_check
can only be applied to functions whose first argument will have attributes named _val1
and _val2
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.