Ваш результирующий код действительно выглядит странно:
a.print_ch()('4') # Call 2
Это потому, что у вас есть один дополнительный слой в декораторе:
def run_in_while_true(f):
def decorator(break_condition=False):
def wrapper(*args, **kwargs):
Декоратор @run_in_while_true
собираетсяreturn decorator
, который должен быть вызван для возврата wrapper
, который должен быть вызван для оценки результата.@run_in_while_true
вызывается автоматически как часть украшения.Два других требуют двух наборов паренов, как показано в вашем коде.
Это проблема, потому что вызов метода, такой как a.print_ch()
, автоматически передает этот вызов первому вызову:
a.print_ch()('4')
# is much the same as
# A.print_ch(self=a)('4')
, который объясняет, почему вы получаете свой инвокант в вашем break_condition.
Я бы посоветовал вам попытаться объединить две внутренние функции.Просто передайте именованный параметр, например break_condition
или break_when
или break_if
, в функцию / метод, и обертка перехватит это одно значение: import functools
def run_until_done(func):
@functools.wraps
def wrapper(*args, break_if=None, **kwargs):
done = break_if if callable(break_if) else lambda: break_if
while not done():
func(*args, **kwargs)
return wrapper
@run_until_done
def print_with_dec(ch):
print ch
print_with_dec('4', break_if=lambda: 1==1 and is_done())