Really sorry for the extremely stupid title, but if I know what it is, I wouldn't write here (:
def some_decorator( func ):
# ..
class A:
@some_decorator
def func():
pass
@fu开发者_高级运维nc.some_decorator # this one here - func.some_decorator ?
def func():
pass
some_decorator
decorates func
- that's OK. But what is func.some_decorator
and how some_decorator
becomes a member ( or something else ? ) of func
?
P.S. I'm 90% sure, that there's such question here (as this seems something basic), but I don't know how to search it. If there's a exact duplicate, I'll delete this question.
Note : It's not typo, nor accident, that both member functions are named func
. The decorator is for overloading: the question is related to Decorating method (class methods overloading)
Remember that the function definition with decorator is equivalent to this:
def func():
pass
func = some_decorator(func)
So in the following lines, func
doesn't refer to the function you defined but to what the decorator turned it into. Also note that decorators can return any object, not just functions. So some_decorator
returns an object with a method (it's unfortunate that the names some_decorator
and func
are reused in the example - it's confusing, but doesn't change anything about the concept) that is itself a decorator. As the expression after the @
is evaluated first, you still have a reference to the first decorator's method after you defined another plain function func
. That decorator is applied to this new function. The full example is then equivalent to this:
class A:
def func():
pass
func = some_decorator(func)
_decorator = func.some_decorator
def func():
pass
func = _decorator(func)
One way to clarify this is to demonstrate it with a concrete example that behaves like this, the builtin property
descriptor:
class C(object):
@property
def x(self):
"This is a property object, not a function"
return self._x
@x.setter
def x(self, val):
self._x = val
>>> c = C()
>>> c.x = 1
>>> c.x
1
>>> C.x
<property object at 0x2396100>
>>> C.x.__doc__
'This is a property object, not a function'
>>> C.x.getter.__doc__
'Descriptor to change the getter on a property.'
>>> C.x.setter.__doc__
'Descriptor to change the setter on a property.'
>>> C.x.deleter.__doc__
'Descriptor to change the deleter on a property.'
The first invocation of property
(as a decorator) means that x
is not a function - it is a property descriptor. A feature of properties is that they allow you to initially define just the fget
method, and then provide fset
and fdel
later by using the property.setter
and property.deleter
decorators (although since each of these creates a new property object, you do need to make sure to use the same name each time).
Something similar will usually be the case whenever you see code using this kind of pattern. Ideally, the naming of the decorators involved will make it reasonably clear what is going on (e.g. most people seem to grasp the idiom for defining property
attributes reasonably easily).
精彩评论