我的装饰器适用于常规功能,但不适用于实例

我有一个工作装饰器,用于在一段时间内运行一个方法 True 并且它在常规函数上运行良好。当我尝试装饰实例的函数时会出现问题。


这是装饰器:


from threading import Thread



def run_in_while_true(f):

    def decorator(break_condition=False):

        def wrapper(*args, **kwargs):

            while True:

                if break_condition:

                    return

                f(*args, **kwargs)

         return wrapper

    return decorator



class A(object):

    @run_in_while_true

    def print_ch(self, ch):

         print ch


@run_in_while_true

def print_with_dec(ch):

     print ch



print_with_dec()('f')  # Call 1

# If i would want to pass a break condition i would write this

print_with_dec(1==1 and 2*2==4)('f')


a = A()

a.print_ch()('4')  # Call 2

`


Call 1 按预期运行并打印了很多。出于某种原因,调用 2 获取了 break_condition 所在的 self 参数,因为对 break_condition 的检查为真并且函数返回。


我需要以何种方式更改装饰器才能使其也适用于对象?提前致谢



浮云间
浏览 187回答 2
2回答

慕桂英3389331

您生成的代码看起来很奇怪: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 functoolsdef 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_donedef print_with_dec(ch):    print chprint_with_dec('4', break_if=lambda: 1==1 and is_done())

明月笑刀无情

感谢大家的帮助,在研究了更多关于从对象调用函数的方式之后,我编写了这些最终的装饰器。它们都适用于对象的常规函数和方法。一个在循环中运行函数直到满足条件,另一个在线程中运行第一个函数,因此程序不会等待。装饰者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 decorateddef 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_oopdef p1(f):    print f@loop_in_thread_oopdef p2(f):    print fif __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
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python