请原谅我关于Python装饰器的另一个问题。我确实读了很多,但是我想知道对于下面这个具体问题,最好的解决方案是什么。在
我用numpy/scipy编写了几个函数来实现某种形式的梯度下降。给定一个矩阵X,我尝试迭代地最小化某个距离d(X,AS),作为a和S的函数。每个算法遵循相同的基本过程,但每个算法都有不同的更新规则。例如,以下是我的两个函数(注意,唯一的区别在于更新规则):
def algo1(X, A=None, S=None, K=2, maxiter=10, c=0.1):
M, N = X.shape
if A is None:
A = matrix(rand(M, K))
if S is None:
S = matrix(rand(K, N))
for iter in range(maxiter):
# Begin update rule.
A = multiply(A, (X*S.T + c)/(A*S*S.T + c))
S = multiply(S, (A.T*X + c)/(A.T*A*S + c))
# End update rule.
for k in range(K):
na = norm(A[:,k])
A[:,k] /= na
S[k,:] *= na
return A, S
。。。另一个:
^{pr2}$这两个功能本身都是成功的。显然,这些函数要求重构。不同的代码单位是更新规则。下面是我的重构尝试:
@iterate
def algo1(X, A=None, S=None, K=2, maxiter=10, c=0.1):
A = multiply(A, (X*S.T + c)/(A*S*S.T + c))
S = multiply(S, (A.T*X + c)/(A.T*A*S + c))
@iterate
def algo2(X, A=None, S=None, K=2, maxiter=10, c=0.1):
A = multiply(A, ((X/(A*S))*S.T + c)/(O*S.T + c))
S = multiply(S, (A.T*(X/(A*S)) + c)/(A.T*O + c))
以下是一些潜在的函数调用:
A, S = algo1(X)
A, S = algo1(X, A0, S0, maxiter=50, c=0.2)
A, S = algo1(X, K=10, maxiter=40)
问题:
iterate
?尤其让我困惑的是参数/参数,例如,没有默认值的vs,在decorator和“wrapper”中访问它们等等。例如,更新规则本身不需要K
,但是初始化代码需要,所以我想知道我的函数签名是否正确。在编辑:谢谢你的帮助。更多问题:
inner
)只有在传递参数时才是必需的吗?因为我看到没有包装器的decorator示例,也没有传递任何参数,它们工作得很好。在functools
似乎很有用;它的主要目的是保留原始函数的元数据(例如,algo1.__name__
和{def algo1(X, A, S, c)
和def inner(X, A=None, S=None, K=2, maxiter=10, c=0.1)
,调用algo1(X, maxiter=20)
仍然有效。从句法上讲,我不知道为什么会这样。为了便于学习,你能澄清(或引用参考文献)?谢谢!在
以下内容应该可以作为您要使用的装饰器:
正如您所注意到的,您可以简化algo1和algo2的签名,但这并不是真正的关键部分,也许保持签名的完整性可以简化测试和重构。如果你想简化,你可以将这些语句的
^{pr2}$def
改为同样地,简化
iterator
修饰中的调用不需要两个参数,也不需要默认值。然而,避免这个简化部分实际上可以使你的生活更简单,如果修饰函数和装饰它的结果,保持彼此完全相同的签名,通常会更简单,除非你真的有相反的特殊需要。在编辑:操作员不断地向这个问题提出问题……:
编辑:谢谢你的帮助。更多问题:
不带参数使用的decorator在
@decorname
中使用时,被修饰的函数被调用,并且必须返回一个函数;一个使用参数的装饰器(如@decorname(23)
)必须返回一个(“高阶”)函数,该函数又被修饰的函数调用,并且必须返回一个函数。无论被修饰的函数是否带参数,都不会更改这组规则。从技术上讲,在没有内部函数的情况下实现这一点是有可能的(我想这就是你所说的“包装器”是什么意思?)但很少有人这样做。在是的,},它有着完全不同的用途)。在
functools.wraps
正是为此目的而使用的(functools
还包含{这是因为
inner
是用这些参数实际调用的函数(在algo1
被修饰之后)并且只传递(到“真正的底层algo1
)参数X, A, S, c
(在被包装的algo1
被赋予简化签名的版本中)。正如我前面提到的,问题在于,这使得被修饰的函数和最终修饰的函数之间的元数据(特别是签名)不同;这使得读取和维护非常混乱,因此通常在两个级别上都保持相同的签名,除特殊情况外。在相关问题 更多 >
编程相关推荐