В качестве декоратора, который вы хотите использовать, должно работать следующее:
import functools
def iterate(update):
@functools.wraps(update)
def inner(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):
A, S = update(X, A, S, K, maxiter, c)
for k in range(K):
na = norm(A[:,k])
A[:,k] /= na
S[k,:] *= na
return A, S
return inner
Как вы заметили, вы могли бы упростить сигнатуры algo1 и algo2, но это на самом деле не важная часть, и, возможно, сохранение нетронутыми сигнатур может упростить ваше тестирование и рефакторинг. Если вы do хотите упростить, вы измените операторы def
для тех, скажем, на
def algo1(X, A, S, c):
и аналогичным образом упрощают вызов в декорации iterator
- нет необходимости ни в двух аргументах, ни в значениях по умолчанию. Однако отказ от этой части упрощения может на самом деле сделать вашу жизнь проще - обычно проще, если декорированная функция и результат ее декорирования сохраняют точно такую же сигнатуру, что и другие, если только у вас нет особых особых требований.
edit : OP продолжает копить вопросы на этот вопрос ...:
РЕДАКТИРОВАТЬ: Спасибо за помощь. Больше вопросов:
Правда ли, что обертка (например,
внутренняя) необходима только когда
параметры передаются? Потому что я
смотрите примеры декораторов без
обертки, и никаких параметров
прошло, и они работают просто отлично.
A декоратор , используемый без параметров (при использовании @decorname
), вызывается с декорируемой функцией и должен возвращать функцию; декоратор, используемый с параметрами (например, @decorname(23)
), должен возвращать функцию ("более высокого порядка"), которая в свою очередь вызывается с декорируемой функцией, и должна возвращать функцию. Независимо от того, принимает ли декорируемая функция параметр или нет, этот набор правил не меняется. Технически возможно достичь этого без внутренних функций (что, я полагаю, вы подразумеваете под «обертками»?), Но это довольно редко.
Из чтения некоторых документов Python
более того, functools кажется полезным; это его
Основная цель сохранения метаданных
исходной функции (например,
algo1. name и algo1. doc )?
Да, functools.wraps
используется именно для этой цели (functools
также содержит partial
, что имеет совершенно другое назначение).
С подписями def algo1(X, A, S,
c)
и def inner(X, A=None, S=None,
K=2, maxiter=10, c=0.1)
, звонок
algo1(X, maxiter=20)
все еще работает.
Синтаксически, я не уверен, почему это
является. Не могли бы вы
уточнить (или привести ссылку)? Спасибо!
Это потому, что inner
- это функция, которая на самом деле вызывается с этими параметрами (после оформления algo1
) и передается только (к «реальным базовым algo1
) параметрам X, A, S, c
(в версии, где обернутый algo1
имеет упрощенную подпись.) Проблема, как я уже упоминал выше, состоит в том, что это делает метаданные (в частности, подпись) различными между декорируемой функцией и результирующей декорированной функцией, что довольно запутанно читать поддерживать, чтобы на обоих уровнях обычно была одна и та же подпись, за исключением особых обстоятельств.