Python 防止函数在一行中被调用两次
我正在学习decorators,我有一项任务要求我创建一个decorator,以防止函数连续被调用两次。如果再次调用相同的函数,则应返回None 我似乎无法理解它到底是如何工作的,到目前为止我已经做到了:Python 防止函数在一行中被调用两次,python,decorator,Python,Decorator,我正在学习decorators,我有一项任务要求我创建一个decorator,以防止函数连续被调用两次。如果再次调用相同的函数,则应返回None 我似乎无法理解它到底是如何工作的,到目前为止我已经做到了: def dont_run_twice(f): global counter def wrapper(*args, **kwargs): counter += 1 if counter == 2: return None
def dont_run_twice(f):
global counter
def wrapper(*args, **kwargs):
counter += 1
if counter == 2:
return None
else:
result = f(*args, **kwargs)
return result
counter = 0
(我知道这是一个非常糟糕的尝试,但我只是不知道如何跟踪使用特定参数调用的函数,以检查它是否已经在之前)
输出应该类似于:
@dont_run_twice
def myPrint(*args):
print(*args)
myPrint("Hello")
myPrint("Hello") #won't do anything (only return None)
myPrint("Hello") #still does nothing.
myPrint("Goodbye") #will work
myPrint("Hello") #will work
似乎这可以帮助你:
import functools
def do_not_run_twice(func):
prev_call = None
@functools.wraps(func) # It is good practice to use this decorator for decorators
def wrapper(*args, **kwargs):
nonlocal prev_call
if (args, kwargs) == prev_call:
return None
prev_call = args, kwargs
return func(*args, **kwargs)
return wrapper
试试这个:
my_print("Hello")
my_print("Hello") # won't do anything (only return None)
my_print("Hello") # still does nothing.
my_print("Goodbye") # will work
my_print("Hello") # will work.
似乎这可以帮助你:
import functools
def do_not_run_twice(func):
prev_call = None
@functools.wraps(func) # It is good practice to use this decorator for decorators
def wrapper(*args, **kwargs):
nonlocal prev_call
if (args, kwargs) == prev_call:
return None
prev_call = args, kwargs
return func(*args, **kwargs)
return wrapper
试试这个:
my_print("Hello")
my_print("Hello") # won't do anything (only return None)
my_print("Hello") # still does nothing.
my_print("Goodbye") # will work
my_print("Hello") # will work.
这是一个与Andrey Berenda的解决方案非常相似的解决方案,但其工作原理是为函数对象指定一个属性,而不是使用非局部变量。实际的区别是,函数以前的参数在外部可用,这可能有助于调试
从functools导入包装
def不运行两次(func):
@包装(func)
def包装(*args,**kwargs):
如果(args,kwargs)=包装器。\u prev\u args:
一无所获
包装器。_prev_args=args,kwargs
返回函数(*args,**kwargs)
包装器。_prev_args=None
返回包装器
例如:
>>@不要运行两次
... 定义f(x,y):
... 返回x+y
...
>>>f(1,2)
3.
>>>f(3,4)
7.
>>>f(3,4)#返回None
>>>f(1,2)
3.
>>>f.(上一页)
((1, 2), {})
请注意,这两种解决方案都有一个轻微的缺陷:如果将它们作为位置参数然后作为关键字参数提供,则可以使用相同的参数值调用(反之亦然):
f(5,6)
11
>>>f(x=5,y=6)
11
作为一种解决方法,您可以使用仅位置(或仅关键字)参数声明包装函数:
#仅限位置,需要Python 3.8+
@不要跑两次
定义f(x,y,/):
返回x+y
#仅关键字
@不要跑两次
定义g(*,x,y):
返回x+y
还要注意,如果前面的参数是可变的,则可能会发生奇怪的事情:
>a=[1,2]
>>>b=[3,4]
>>>f(a,b)
[1, 2, 3, 4]
>>>a[:]=[5,6]
>>>b[:]=[7,8]
>>>f([5,6],[7,8])#返回无
这里的第二个函数调用返回
None
,尽管新参数的值或标识与原始参数不相等;它们等于原始参数的当前值,这些值在用作参数后更改。这可能会导致相当微妙的错误,但不幸的是,没有简单的方法来修复它。这里有一个与Andrey Berenda的解决方案非常相似的解决方案,但它通过为函数对象指定属性而不是使用非局部变量来工作。实际的区别是,函数以前的参数在外部可用,这可能有助于调试
从functools导入包装
def不运行两次(func):
@包装(func)
def包装(*args,**kwargs):
如果(args,kwargs)=包装器。\u prev\u args:
一无所获
包装器。_prev_args=args,kwargs
返回函数(*args,**kwargs)
包装器。_prev_args=None
返回包装器
例如:
>>@不要运行两次
... 定义f(x,y):
... 返回x+y
...
>>>f(1,2)
3.
>>>f(3,4)
7.
>>>f(3,4)#返回None
>>>f(1,2)
3.
>>>f.(上一页)
((1, 2), {})
请注意,这两种解决方案都有一个轻微的缺陷:如果将它们作为位置参数然后作为关键字参数提供,则可以使用相同的参数值调用(反之亦然):
f(5,6)
11
>>>f(x=5,y=6)
11
作为一种解决方法,您可以使用仅位置(或仅关键字)参数声明包装函数:
#仅限位置,需要Python 3.8+
@不要跑两次
定义f(x,y,/):
返回x+y
#仅关键字
@不要跑两次
定义g(*,x,y):
返回x+y
还要注意,如果前面的参数是可变的,则可能会发生奇怪的事情:
>a=[1,2]
>>>b=[3,4]
>>>f(a,b)
[1, 2, 3, 4]
>>>a[:]=[5,6]
>>>b[:]=[7,8]
>>>f([5,6],[7,8])#返回无
这里的第二个函数调用返回
None
,尽管新参数的值或标识与原始参数不相等;它们等于原始参数的当前值,这些值在用作参数后更改。这可能会导致相当微妙的错误,但不幸的是,没有简单的方法来修复它。关于“特定参数”有什么评论?您是否希望将myPrint('a')
和myPrint('b')
视为不同?是的,这正是我想要的。当装饰器应用于多个函数时,使用global
将在此处给出错误的结果。关于“特定参数”的注释是什么?您是否希望将myPrint('a')
和myPrint('b')
视为不同?是的,这正是我想要的。当装饰器应用于多个函数时,使用global
将在此处给出错误的结果。实际上,我希望最后一次myu print('Hello')能够工作,该函数不应连续调用两次,而不是两次,您不能使用set,因为您的参数不能散列。使用set尝试my_print([]),它将error@MM1我已经更改了答案。这不支持关键字。最好使用(args,kwargs)
元组来检查以前的调用参数,而不仅仅是args
。实际上,我希望最后一次打印(“Hello”)能够正常工作,函数不应该连续调用两次,而不是两次。不,您不能使用set,因为您的args不能散列。使用set尝试my_print([]),它将error@MM1我已经更改了答案。这不支持关键字。最好使用(args,kwargs)
的元组来检查以前的调用参数,而不仅仅是args
。