开发者

How is this called and how can be done ( `function_name.decorator` )?

开发者 https://www.devze.com 2023-03-06 06:11 出处:网络
Really sorry for the extremely stupid title, but if I know what it is, I wouldn\'t write here (: def some_decorator( func ):

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).

0

精彩评论

暂无评论...
验证码 换一张
取 消