Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在不丢失方法绑定状态的情况下动态修饰类方法?_Python_Python 3.x - Fatal编程技术网

Python 如何在不丢失方法绑定状态的情况下动态修饰类方法?

Python 如何在不丢失方法绑定状态的情况下动态修饰类方法?,python,python-3.x,Python,Python 3.x,假设我有一个这样的装饰师: def repeat(repeat_count): def decorator(func): def wrapped(self): for X in range(repeat_count): func() # Do Function return wrapped return decorator 还有像这样的课 class SomeClass(object):

假设我有一个这样的装饰师:

def repeat(repeat_count):
    def decorator(func):
        def wrapped(self):
            for X in range(repeat_count):
                 func() # Do Function
        return wrapped
    return decorator
还有像这样的课

class SomeClass(object):
    def __init__(self, do_count):
        self.some_method = repeat(do_count)(self.some_method)

    def some_method(self): 
        print("I'm Doing Something")
因为装饰器只是返回一个方法,很明显这是可行的。但是,它将some_method函数从类实例中解除绑定,因此我无法再执行以下操作:

>>> sc = SomeClass(10)
>>> sc.some_method()
# TypeError: wrapped() missing 1 required positional argument: 'self'
我得到一个异常,因为self不再自动传递。为了实现这一目标,我可以简单地做到:

sc.some_method(sc)
但我宁愿不要。是否有任何方法可以将方法重新绑定到实例,最好不需要任何额外的导入(如TypeMethod)就可以完成

我得到一个异常,因为self不再自动传递

实际上,它仍然是自动传递的。出现此异常是因为定义装饰器的方式要求它被传递两次

在wrapped的运行时中,
func
已经绑定(即它已经自我传递)。通过定义
wrapped
来接受一个位置参数,您需要再次传入
self
,这就是
sc的原因。某些方法(sc)
工作正常。
self
根据需要传递两次-一次隐式传递,一次显式传递

对代码的最小修复是从
wrapped
的签名中删除
self
,因为该签名已根据
self.some\u方法的绑定中的描述符协议隐式传递

def repeat(repeat_count):
    def decorator(func):
        def wrapped():
            for X in range(repeat_count):
                 func() # Do Function
        return wrapped
    return decorator
然而,这并不是最好的解决方案。您需要接受
*args
**kwargs
,这样无论修饰函数的签名如何,都可以应用修饰符:

def repeat(repeat_count):  # <-- the "decorator maker"
    def decorator(func):  # <-- the decorator
        def wrapped(*args, **kwargs):  # <-- this will replace "func"
            for X in range(repeat_count):
                 func(*args, **kwargs)  # <-- note: pass along the arguments!
        return wrapped  # <-- note: no call here!
    return decorator

def repeat(repeat_count):#对于一个相当简单的情况,您不需要从decorator本身访问
self
,您可以简单地使用以下命令(这与您已经做的差不多,减去包装器函数调用和
self
的传递)。 分配时,传递给装饰器的方法已绑定到self

self.some_method = repeat(do_count)(self.some_method)
完整代码:

def repeat(repeat_count):
    def decorator(func):
        def wrapped():
            for X in range(repeat_count):
                 func()
        return wrapped
    return decorator


class SomeClass(object):
    def __init__(self, do_count):
        self.a = 3
        self.some_method = repeat(do_count)(self.some_method)

    def some_method(self): print("Accesing my a from inside: %d" % self.a)


sc = SomeClass(5)
sc.some_method()
输出:

Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3
Accesing my a from inside: 3

对不起,那是个打字错误。这只是一个例子。在我实际做的事情中,我使用了args和kwargs,所以不用担心。如果你在正确的位置使用*args和**kwargs,那么你一开始就不会有错误,所以…@wim如果我想通过使用
包装的
范围访问实例的某些属性,该怎么办?我试图在
SomeClass
\uuuuu init\uuuuuu
中设置以下内容:
self.some\u方法=重复(do\u计数)(SomeClass.some\u方法)
并将
self
作为位置参数添加到
wrapped
函数中。尽管如此,调用
sc=SomeClass(5)sc.some_method()
会导致与@MohsinKale'相同的错误s@EliranAbdoo在
wrapped
内部,实例可以作为
func.\uuuuu self\uuuuu
使用。我所做的只是在返回它时调用wrapped方法。这只是我在不到3分钟内写的一个例子,让我放松一下。至于repost声明,我已经明确表示,我更愿意避免任何额外的导入,因为您链接到的帖子中给出了主要的解决方案。这个问题的答案不需要任何导入。使用“动态修饰”是指在init方法中显式修饰(或者至少不使用@syntax)?正如@wim所说的-请不要进行使您收到的答案无效的编辑。谢谢。@JonClements很不幸,现在的答案中不再提到问题,但答案没有回答Moshin想问的问题。他没有通过编辑来改变他的问题,而是进行了编辑以使问题更清楚。因为打字错误而不得不提出一个新问题对我来说似乎毫无帮助。