我希望能够根据某种标准格式调用方法:
outputs = obj.meth(in_0, in_1, ...),其中输出是数组的元组,每个输入是一个数组。
但是,在大多数情况下,我只返回一个数组,并且不希望为了标准格式而强制返回长度为1的元组。 (我的实际格式化问题更复杂,但现在暂时坚持这个解释。)
我希望能够定义一个类:
class _SomeClass(object): def __init__(self): self._amount_to_add = 1 @single_return_format def add_one(self, x): return x+self._amount_to_add然后可以按如下方式调用它:
obj = _SomeClass() assert obj.add_one(3) == 4 assert obj.add_one.standard_format(3)==(4, )问题是:如何定义装饰器以允许此行为?
我试过了:
def single_return_format(fcn): fcn.standard_format = lambda *args: (fcn(*args), ) return fcn,但它在第二个断言的行上失败:
TypeError: add_one() takes exactly 2 arguments (1 given)因为add_one需要“self”作为参数,并且在装饰器修改函数时甚至还没有创建对象。
那么Stack,我该怎么做?
笔记:
1)我知道我可以用基类和继承来做这件事,但是如果你想在这个方法中装饰多个方法,这就成了一个问题。
2)实际问题来自使用theano - 标准格式是outputs, updates = fcn(*inputs) ,但大多数函数不返回任何更新,因此您希望能够以自然方式定义这些函数,但是仍然可以根据此标准界面调用它们。
I want to be able to call a method according to some standard format:
outputs = obj.meth(in_0, in_1, ...), where outputs is a tuple of arrays, and each input is an array.
However, in most instances, I only return one array, and don't want to be forced to return a tuple of length 1 just for the sake of the standard format. (My actual formatting problem is more complicated but lets stick with this explanation for now.)
I want to be able to define a class like:
class _SomeClass(object): def __init__(self): self._amount_to_add = 1 @single_return_format def add_one(self, x): return x+self._amount_to_addAnd then be able to call it as follows:
obj = _SomeClass() assert obj.add_one(3) == 4 assert obj.add_one.standard_format(3)==(4, )Question is: how do I define the decorator to allow this behaviour?
I tried:
def single_return_format(fcn): fcn.standard_format = lambda *args: (fcn(*args), ) return fcn, but it fails on the line with the second assert with:
TypeError: add_one() takes exactly 2 arguments (1 given)Because the add_one requires "self" as an argument, and the the object has not even been created yet at the time the decorator modifies the function.
So Stack, how can I do this?
Notes:
1) I know I could do this with base-classes and inheritance instead, but that becomes a problem when you have more than one method in the class that you want to decorate this way.
2) The actual problem comes from using theano - the standard format is outputs, updates = fcn(*inputs), but most functions don't return any updates, so you want to be able to define those functions in a natural way, but still have the option of calling them according to this standard interface.
最满意答案
这确实是一个问题,因为从函数中检索“绑定”方法的方式不考虑这种方式。
我看到两种方式:
你可以包装函数:
def single_return_format(fcn): # TODO Do some functools.wraps here... return lambda *args, **kwargs: (fcn(*args, **kwargs), )不要愚弄.standard_format ,但仅仅是替换功能。 所以函数可以将自己定义为返回一个值,但只能被调用为返回元组。
如果这不是你想要的,你可以定义一个用于装饰方法的类,它覆盖__get__并以“实时方式”进行包装。 当然,它也可以重新定义__call__以便它也可用于(独立的,非方法)函数。
Dunes gave the correct answer. I've stripped it down to bare bones so that it solves the problem in the question. The stripped-down code is here:
class single_return_format(object): def __init__(self, func): self._func = func def __get__(self, instance, owner): return SimpleFormMethod(instance, self._func) class SimpleFormMethod(object): def __init__(self, instance, func): self._instance = instance self._func = func def __call__(self, *args, **kwargs): return self._func(self._instance, *args, **kwargs) @property def standard_format(self): return lambda *args, **kwargs: (self._func(self._instance, *args, **kwargs), ) class _SomeClass(object): def __init__(self): self._amount_to_add = 1 @single_return_format def add_one(self, x): return x+self._amount_to_add obj = _SomeClass() assert obj.add_one(3) == 4 assert obj.add_one.standard_format(3) == (4, )更多推荐
发布评论