【发布时间】:2010-02-21 14:32:34
【问题描述】:
请原谅我提出另一个关于 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
...和其他:
def algo2(X, A=None, S=None, K=2, maxiter=10, c=0.1):
M, N = X.shape
O = matrix(ones([M, N]))
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/(A*S))*S.T + c)/(O*S.T + c))
S = multiply(S, (A.T*(X/(A*S)) + c)/(A.T*O + c))
# End update rule.
for k in range(K):
na = norm(A[:,k])
A[:,k] /= na
S[k,:] *= na
return A, S
这两个功能都是成功的。显然,这些功能要求重构。不同的代码单元是更新规则。所以这是我的重构尝试:
@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. 没有默认值,在装饰器和“包装器”中访问它们等等。例如,更新规则本身不需要K,但是初始化代码确实如此,所以我想知道我的函数签名是否正确。
编辑:感谢您的帮助。更多问题:
- 是否只有在传递参数时才需要包装器(例如
inner)?因为我看到没有包装器的装饰器示例,并且没有传递任何参数,它们工作得很好。 - 通过阅读更多 Python 文档,
functools似乎很有用;它的主要目的是保留原始函数的元数据(例如,algo1.__name__和algo1.__doc__)? - 使用签名
def algo1(X, A, S, c)和def inner(X, A=None, S=None, K=2, maxiter=10, c=0.1),调用algo1(X, maxiter=20)仍然有效。从语法上讲,我不确定为什么会这样。出于学习目的,您能否澄清(或引用参考)?谢谢!
【问题讨论】:
-
我建议把装饰器的名字改成更有意义的名字——“迭代”在 Python 中已经有了特定的含义。 “gradient_descent”或“minimise_matrix_distance”怎么样?
-
是的,在我的原始代码中,装饰器和函数名称是不同的。谢谢你的建议。
标签: python refactoring numpy decorator