![](/img/trans.png)
[英]Python: can I use the lambda argument n to repeat lambda operation (n+n) n times?
[英]Python3 'repeat' decorator with argument: @repeat(n)
我已經看過(很棒的)許多帶w和w / o參數的裝飾器的教程和片段,包括我認為可以視為規范的答案的兩個: 帶參數的 裝飾器,帶@語法的python裝飾器參數 ,但我不明白為什么我的代碼中出現錯誤。
以下代碼位於文件decorators.py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Description: decorators
"""
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
while nbrTimes != 0:
nbrTimes -= 1
return func(*args, **kwargs)
return wrapper_repeat
return real_repeat
我從語法檢查器收到的第一個警告是nbrTimes
是一個“未使用的參數”。
我在python3交互式控制台中使用以下命令測試了上述內容:
>>> from decorators import repeat
>>> @repeat(nbrTimes=3)
>>> def greetings():
>>> print("Howdy")
>>>
>>> greetings()
Traceback (most recent call last):
File "<stdin>", line 1 in <module>
File path/to/decorators.py, line xx in wrapper_repeat
'''
UnboundLocalError: local variable 'nbrTimes' referenced before assignment.
我只是看不到我在哪里亂扯。 在其他示例中,直到稍后在內部函數中才使用“傳遞的參數”(此處為nbrTimes
),因此執行時出現的“未使用的參數”警告和錯誤使我nbrTimes
。 對於Python來說還是相對較新的。 幫助非常感謝。
編輯:( 響應@recnac的重復標志)根本不清楚您聲稱的重復項中要實現的OP。 我只能推測他/她打算從全局范圍訪問裝飾器包裝器內定義的計數器,但未能將其聲明為nonlocal
。 事實是,我們甚至都不知道OP處理的是Python 2還是3,盡管在這里與OP無關。 我向您承認錯誤消息非常相似,如果不相同,甚至不相同。 但是,我的目的不是從全局范圍訪問包裝器內定義的計數器。 我打算使這個計數器純粹是本地化的,並且做到了。 我的編碼錯誤在其他地方。 事實證明,凱文(下面)提供的出色的討論和解決方案是自然的,與在包裝器定義塊內添加nonlocal <var>
完全不同(對於Python 3.x)。 我不會重復凱文的論點。 它們清澈透明,可供所有人使用。
最終,我走了出去,會說錯誤消息可能是這里所有問題中最不重要的,即使這顯然是我的錯誤代碼造成的。 為此,我做出了修改,但此職位絕對不是對提議的“重復”內容的重新討論。
提出的重復問題“ python裝飾器中的變量范圍-更改參數”提供了有用的信息,這些信息解釋了為什么wrapper_repeat
認為nbrTimes
是局部變量,以及如何使用nonlocal
局部變量來使其識別由repeat
定義的nbrTimes
。 這樣可以解決該異常,但是對於您的情況,我認為這不是一個完整的解決方案。 裝飾的功能仍然不會重復。
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
nonlocal nbrTimes
while nbrTimes != 0:
nbrTimes -= 1
return func(*args, **kwargs)
return wrapper_repeat
return real_repeat
@repeat(2)
def display(x):
print("displaying:", x)
display("foo")
display("bar")
display("baz")
結果:
displaying: foo
displaying: bar
“ foo”和“ bar”分別僅顯示一次,而“ baz”則顯示0次。 我認為這不是理想的行為。
由於while
循環內有return func(*args, **kwargs)
因此無法重復display
的前兩個調用。 return語句使wrapper_repeat
立即終止,並且while
不會再進行任何迭代。 因此,任何修飾功能都不會重復一次以上。 一種可能的解決方案是刪除return
並僅調用該函數。
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
nonlocal nbrTimes
while nbrTimes != 0:
nbrTimes -= 1
func(*args, **kwargs)
return wrapper_repeat
return real_repeat
@repeat(2)
def display(x):
print("displaying:", x)
display("foo")
display("bar")
display("baz")
結果:
displaying: foo
displaying: foo
“ foo”被顯示兩次,但是現在“ bar”和“ baz”都沒有出現。 這是因為nbrTimes
跨你的裝飾的所有實例,由於共享nonlocal
。 一旦display("foo")
nbrTimes
減為零,即使調用完成后,它仍保持為零。 display("bar")
和display("baz")
將執行其裝飾器,看到nbrTimes
為零,並終止而nbrTimes
不調用裝飾的函數。
因此,事實證明您不希望循環計數器是非本地的。 但這意味着您不能為此目的使用nbrTimes
。 嘗試根據nbrTimes
的值創建一個局部變量,然后遞減該變量。
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
times = nbrTimes
while times != 0:
times -= 1
func(*args, **kwargs)
return wrapper_repeat
return real_repeat
@repeat(2)
def display(x):
print("displaying:", x)
display("foo")
display("bar")
display("baz")
結果:
displaying: foo
displaying: foo
displaying: bar
displaying: bar
displaying: baz
displaying: baz
...並且在使用時,最好使用for
循環而不是while
。
import functools
def repeat(nbrTimes=2):
'''
Define parametrized decorator with arguments
Default nbr of repeats is 2
'''
def real_repeat(func):
"""
Repeats execution 'nbrTimes' times
"""
@functools.wraps(func)
def wrapper_repeat(*args, **kwargs):
for _ in range(nbrTimes):
func(*args, **kwargs)
return wrapper_repeat
return real_repeat
@repeat(2)
def display(x):
print("displaying:", x)
display("foo")
display("bar")
display("baz")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.