2

调用装饰器时,似乎 mymethod 还不是方法。

import inspect

class decorator(object):
    def __call__(self, call):
        if inspect.ismethod(call): #Not working yet
            obj = "method"
            args = inspect.getargspec(call)[0][1:]
        elif inspect.isfunction(call):
            obj = "function"
            args = inspect.getargspec(call)[0]
        elif inspect.isclass(call):
            obj = "class"
            args = inspect.getargspec(call.__init__)[0][1:]

        args="(%s)" % repr(args)[1:-1].replace("'","")
        print "Decorate %s %s%s" % (obj, call.__name__, args)
        return call


@decorator()
def myfunction (a,b): pass

@decorator()
class myclass():
    def __init__(self, a, b): pass

    @decorator()
    def mymethod(self, a, b): pass

if inspect.isfunction(myclass.mymethod):
    print "mymethod is a function"
if inspect.ismethod(myclass.mymethod):
    print "mymethod is a method"

输出:

Decorate function myfunction(a, b)
Decorate function mymethod(self, a, b)
Decorate class myclass(a, b)
mymethod is a method

我会知道第一个参数是否是“自我”,但会有一个不那么肮脏的解决方案吗?

编辑:为什么?

我想填充一个可调用对象及其参数的列表,如果它是一个函数或一个类,我可以传递预期的参数,然后我调用它,但如果它是一个方法,我没有“self”参数可以传递. 就像是:

import inspect

class ToDo(object):
    calls=[]

    def do(self, **kwargs):
        for call in self.calls:
            if 'self' in call.args:
                print "This will fail."
            args = {}
            for arg in call.args:
                args[arg]=kwargs.get(arg, None)
            call.call(**args)

TODO = ToDo()

class decorator(object):
    def __call__(self, call):
        if inspect.isfunction(call):
            args = inspect.getargspec(call)[0]
        elif inspect.isclass(call):
            args = inspect.getargspec(call.__init__)[0][1:]

        self.call = call
        self.args = args
        TODO.calls.append(self)
        return call

TODO.do(a=1, b=2)
4

2 回答 2

1

你不能真正区分。这是一个例子:

>>> class A(object):
...    pass
...
>>> def foo(x): return 3
...
>>> A.foo = foo
>>> type(foo)
<type 'function'>
>>> type(A.foo)
<type 'instancemethod'>

如您所见,您的装饰器可以应用于foo,因为它是一个函数。但是您可以简单地创建一个引用该函数的类属性来创建装饰方法。

(此示例来自 Python 2.7;我不确定 Python 3 中是否发生了任何更改以使上述行为有所不同。)

于 2013-05-18T14:03:14.917 回答
0

您无法从函数中分辨出方法,但您可以检查第一个参数是否看起来像 self:

def __call__(self, func):
    def new_func(*args, **kw):
        if len(args) and hasattr(args[0], '__dict__') \
                and '__class__' in dir(args[0]) and func.__name__ in dir(args[0])\
                and '__func__' in dir(getattr(args[0], func.__name__))\
                and getattr(args[0], func.__name__).__func__ == self.func:
            return my_func(*args[1:], **kw)
        else:
            return my_func(*args, **kw)

    self.func = new_func
    return new_func

但这不适用于嵌套装饰器 - 下一个装饰器将更改函数并且与 self.func 的比较将不起作用。

另一种方法 - 检查装饰函数的第一个参数的名称是否为 self - 这是 Python 中非常强大的约定,因此可能足够好:

def __call__(self, func):
    def new_func(*args, **kw):
        if len(inspect.getfullargspec(func).args)\
           and inspect.getfullargspec(func).args[0] == 'self':
            return my_func(*args[1:], **kw)
        else:
            return my_func(*args, **kw)

    self.func = new_func
    return new_func
于 2017-04-25T08:34:06.277 回答