Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.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_Decorator_Nose_Python Decorators - Fatal编程技术网

Python 装饰实例方法并从装饰器调用它

Python 装饰实例方法并从装饰器调用它,python,decorator,nose,python-decorators,Python,Decorator,Nose,Python Decorators,我使用nose特性在不同的上下文中运行相同的测试。因为每次试验都需要以下锅炉板: class TestSample(TestBase): def test_sample(self): for context in contexts: yield self.check_sample, context def check_sample(self, context): """The real test logic is imp

我使用nose特性在不同的上下文中运行相同的测试。因为每次试验都需要以下锅炉板:

class TestSample(TestBase):

    def test_sample(self):
        for context in contexts:
            yield self.check_sample, context

    def check_sample(self, context):
        """The real test logic is implemented here"""
        pass
我决定写下面的decorator:

def with_contexts(contexts=None):        
    if contexts is None:
        contexts = ['twitter', 'linkedin', 'facebook']

    def decorator(f):
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            for context in contexts:
                yield f, self, context # The line which causes the error
        return wrapper
    return decorator
装饰器的使用方式如下:

class TestSample(TestBase):  

    @with_contexts()
    def test_sample(self, context):
        """The real test logic is implemented here"""
        var1 = self.some_valid_attribute
执行测试时,将抛出一个错误,指定正在访问的属性不可用。但是,如果我将调用该方法的行更改为以下内容,则它可以正常工作:

yield getattr(self, f.__name__), service
我知道上面的代码片段创建了一个绑定方法,其中与第一个self一样,手动将绑定方法传递给函数。然而,就我的理解而言,第一个片段也应该可以很好地工作。如果有人能澄清这个问题,我将不胜感激


这个问题的标题通常与在decorators中调用实例方法有关,但我保留了特定于我上下文的描述。

您可以使用
functools.partial
将包装函数绑定到
self
,就像方法一样:

from functools import partial

def decorator(f):
    @wraps(f)
    def wrapper(self, *args, **kwargs):        
        for context in contexts:
            yield partial(f, self), context
    return wrapper

现在您将生成partials,当它被称为
yielddevalue(context)
时,将调用
f(self,context)

据我所知,有些东西不适合在一起。首先,你的装饰师就像

def with_contexts(contexts=None):        
    if contexts is None:
        contexts = ['twitter', 'linkedin', 'facebook']

    def decorator(f):
        @wraps(f)
        def wrapper(self, *args, **kwargs):
            for context in contexts:
                yield f, self, context # The line which causes the error
        return wrapper
    return decorator
但你用起来就像

@with_contexts
def test_sample(self, context):
    """The real test logic is implemented here"""
    var1 = self.some_valid_attribute
这是错误的:它使用上下文调用
(test\u sample)
,但您需要使用上下文()调用
(test\u sample)
。我也是

@with_contexts()
def test_sample(self, context):
    """The real test logic is implemented here"""
    var1 = self.some_valid_attribute
即使您没有提供
上下文
参数

其次,您修饰了错误的函数:您的用法表明,
test
函数为每个上下文生成了
check
函数。要包装的函数执行检查函数的工作,但必须在测试函数之后命名

self
应用于一个方法可以像Martijn写的那样使用
partial
完成,但也可以像Python在幕后那样:使用

method.__get__(self, None)
或者更好

method.__get__(self, type(self))

你也可以做到这一点。(也许您的原始版本也可以使用,可以生成要调用的函数和要使用的参数。我不清楚它是否是这样工作的。)

感谢您的回复。据我所知,装饰器生成一个元组,其中第一个元素是函数,第二个是对对象的引用,然后。。。为什么它在第一种情况下抛出错误,而不是在第二种情况下抛出错误?顺便说一句:partials似乎很酷。因为在第一种情况下,您产生了三个值,而不是两个。通常,您需要生成方法和上下文,您是在生成函数,
self
和上下文。传递给decorator的函数是未绑定的方法吗?如果我将self作为第一个参数传递给它,它是否会表现得不符合预期?我知道我在这里遗漏了一些东西,如果你能启发我,我将不胜感激。装饰器被赋予了一个函数,甚至不是一个未绑定的方法。修饰发生在定义类之前,方法绑定发生在通过实例或类的属性访问查找方法时(后者是未绑定的方法,前者是绑定的方法)。通过使用partial,您将self作为第一个参数传递,但是无论调用什么,您的方法都不需要多个参数。您没有包含完整的回溯,所以我在这里猜测。专业提示:当您在Python中遇到错误时,请在您的问题中包含完整的回溯,这样我们就不必猜测您到底出了什么问题。没有“()”操作符的装饰器调用是一个错误,请更正。我提出decorator的原因是为了避免循环的样板代码和另一种方法。让我困惑的是,如果将“self”作为第一个参数传递给无界方法,为什么它不能访问属于它的属性(self)。我的理解似乎有差距。@Ifthikhan因为你还没有告诉我们异常情况(包括回溯),我们无法确切地说出问题所在。看起来它应该会起作用,但从这里很难说到底出了什么问题。。。你可以用一个
打印自我
来显示真正在这里的内容,而不是应该在这里的内容。