2 回答
TA贡献2036条经验 获得超8个赞
您生成的代码看起来很奇怪:
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装饰是要回报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())
TA贡献1828条经验 获得超4个赞
感谢大家的帮助,在研究了更多关于从对象调用函数的方式之后,我编写了这些最终的装饰器。它们都适用于对象的常规函数和方法。一个在循环中运行函数直到满足条件,另一个在线程中运行第一个函数,因此程序不会等待。
装饰者
def loop_in_while_oop(f):
""" Runs a function in a loop, params have to be passed by name"""
def decorated(self=None, break_if=None, *args,**kwargs):
"""
:param self: Will be passed automatically if needed
:param break_if: Lambada expression for when to stop running the while loop
"""
done = break_if if callable(break_if) else lambda: break_if
while not done():
if self is not None:
f(self, *args, **kwargs)
else:
f(*args, **kwargs)
return decorated
def loop_in_thread_oop(f):
""" Runs function in a loop in a thread, MUST: pass arguments by name"""
def decorated(self=None, break_if=lambda: False, *args, **kwargs):
"""
:param self: Will be passed automatically if needed
:param break_if: Lambada expression for when to stop running the while loop, if value not passed will run forever
"""
f1 = loop_in_while_oop(f)
t = Thread(target=f1, args=args, kwargs=dict(self=self, break_if=break_if, **kwargs))
t.start()
return decorated
使用装饰器
class SomeObj(object):
@loop_in_thread_oop
def print_c(self, c):
print c
@loop_in_thread_oop
def p1(f):
print f
@loop_in_thread_oop
def p2(f):
print f
if __name__ == '__main__':
a = SomeObj()
start = time.time()
a.print_c(c='a') # Will run forever because break_if was not specified
p1(f='3', break_if=lambda: time.time() - start > 3) # Will stop after 3 seconds
p2(f='5', break_if=lambda: time.time() - start > 5) # Will stop after 5 seconds
输出:
0-3 秒之间:打印a35(顺序不固定)
3-5 秒之间:打印a5(顺序不固定)
3-5 秒之间:打印a
添加回答
举报