Это происходит потому, что вы перекрашиваете уже оформленную функцию.
После первой итерации:
for link in links:
# Decorator
print_url = cycle(link)(print_url)
print_url()
Тогда print_url
относится к inner_wrapper
.Вы украшаете inner_wrapper
снова.Это не имеет ничего общего с сборкой мусора, это просто то, что вы написали для этого.
Это становится более понятным, если вы удалите wraps
:
def cycle(url):
def outer_wrapper(func):
state = 0
def inner_wrapper(**kwargs):
nonlocal state
state += 1
kwargs['url'] = url
if state == 1:
print('Returning result at first execution on {} with: '
'state => {}, kwargs => {}'.format(func, state, kwargs))
return func(**kwargs)
else:
print('Returning result at upcoming executions on {} with: '
'state => {}, kwargs => {}'.format(func, state, kwargs))
return func(**kwargs)
return inner_wrapper
return outer_wrapper
def print_url(url):
print('Returned from print_url function:', url)
links = ['an-url', 'another-url']
for i, link in enumerate(links):
print("Iteration :", i)
print_url = cycle(link)(print_url)
print_url()
И вывод терминала:
Iteration : 0
Returning result at first execution on <function print_url at 0x1060892f0> with: state => 1, kwargs => {'url': 'an-url'}
Returned from print_url function: an-url
Iteration : 1
Returning result at first execution on <function cycle.<locals>.outer_wrapper.<locals>.inner_wrapper at 0x106089378> with: state => 1, kwargs => {'url': 'another-url'}
Returning result at upcoming executions on <function print_url at 0x1060892f0> with: state => 2, kwargs => {'url': 'an-url'}
Returned from print_url function: an-url
Если вы хотите получить доступ к исходной функции, япредлагаем просто сохранить ссылку на него вне цикла и не присваивать результат декоратора этой переменной, например:
original_function = print_url
for link in links:
# Decorator
print_url = cycle(link)(original_function)
print_url()
print_url = original_function
просто для удовольствия, вы могли бы восстановить егона каждой итерации делали что-то с эффектом:
for link in links:
# Decorator
print_url = cycle(link)(print_url)
print_url()
closure = print_url.__closure__
idx_func = print_url.__code__.co_freevars.index('func')
print_url = closure[idx_func].cell_contents
Но ... это просто ужасный беспорядок, который раскрывает кучу внутренних деталей, которые лучше оставить под капотом.
Принципиально, Я не уверен, зачем здесь нужен декоратор, то есть в чем преимущество использования этого декоратора?