我的装饰器可用于常规功能,但不能用于临时安装

时间:2019-02-08 07:06:59

标签: python python-2.7 decorator

我有一个工作的装饰器,可以在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

`

呼叫1按预期运行,并且打印很多。 出于某种原因,调用2会获得self参数,其中break_condition为break,并且因为break_condition的检查为true并返回函数。

我需要以哪种方式更改装饰器,使其也可以与对象一起使用?预先感谢

2 个答案:

答案 0 :(得分:0)

您得到的代码看起来真的很奇怪:

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()作为装饰的一部分被自动调用。如代码中所示,另外两个需要两套paren。

这是一个问题,因为方法调用(如a.print_ch()('4') # is much the same as # A.print_ch(self=a)('4') 会自动将倡导者传递给第一个调用:

break_condition.

这说明了为什么您会在break_condition中引起拥护者

我建议您尝试统一两个内部功能。只需将诸如break_whenbreak_ifdef 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()) 之类的命名参数传递给函数/方法,并让包装器截获该值:     导入功能工具

Approach 1
public sealed class Singleton {
    //Private ctor of course :P
    private Singleton() {}
    // Instance property to access Singleton Instance
    public static Singleton Instance { get { return Nested.instance; } }

    private class Nested {

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() { }

        internal static readonly Singleton instance = new Singleton();
    }
}

Approach 2
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
 }
}

答案 1 :(得分:0)

感谢大家的帮助,在深入研究了从对象调用函数的方式之后,我编写了这些最终修饰符。它们都适用于常规功能和对象方法。一个循环运行该函数直到满足条件为止,另一个循环在线程中运行第一个函数,因此程序无需等待。

装饰器

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