Python 装饰实例方法并从装饰器调用它
我使用nose特性在不同的上下文中运行相同的测试。因为每次试验都需要以下锅炉板: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
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因为你还没有告诉我们异常情况(包括回溯),我们无法确切地说出问题所在。看起来它应该会起作用,但从这里很难说到底出了什么问题。。。你可以用一个打印自我
来显示真正在这里的内容,而不是应该在这里的内容。