代码之家  ›  专栏  ›  技术社区  ›  abhishek_rathaur

蟒蛇装饰器

  •  -1
  • abhishek_rathaur  · 技术社区  · 6 年前
    from random import randint
    import  time
    state = 0 #close
    
    open_time = 0
    failure_count = 0
    count = 0
    status = {0 : "closed" , 2 : " open" , 1 : "half closed"}
    def circuitbreaker(func):
        global count
        global open_time , state
        print("circuit status "+ status.get(state))
        if state ==0: #close state
            try:
                func()
            except Exception as ex:
                print(ex)
                count+=1
                if count>2:
                    print("opening circuit breaker")
                    state = 2
                    open_time = int(time.time())
        elif (state == 2): #open state
            if( time.time() - open_time > 5) :
                state = 1
            else:
                print("circuit opened")
        else:
            try:
                func()
                count = 0
                open_time = 0
                print("closing circuit breaker")
                state = 0
            except Exception as ex:
                state = 2
                open_time = int(time.time())
                print("opening circuit breaker")
    
    @circuitbreaker
    def generic_func():
        a = randint(0,9)
        print("hello")
        print("random number = "+str(a))
        if a>4:
            return a
        else:
            raise Exception('Yalla!')
    
    if __name__=="__main__":
    
        # while(True):
        #     generic_func()
            time.sleep(1)
    

    我有这个密码。我有几个问题: 1)为什么调用泛型函数,即使我在main中对其进行了注释。

    2)在主函数中取消注释注释部分时。我得到以下错误。如何正确调用此泛型函数。 我的动机是实现一个断路器,当调用函数中出现某种错误或异常时,断路器将闭合。我可以直接使用: 断路器(调用函数),但我想使用decorators

    Traceback (most recent call last):
    circuit status closed
    hello
      File "/Users/abhishekkumar/PycharmProjects/RateLimiter/circuitbreaker.py", line 53, in <module>
    random number = 1
    Yalla!
        generic_func()
    TypeError: 'NoneType' object is not callable
    
    Process finished with exit code 1
    

    问题是decorator应该返回一个函数对象,并且应该在函数中包含相关逻辑,然后返回该函数,否则它将不返回任何对象。

    3 回复  |  直到 6 年前
        1
  •  2
  •   Dan D.    6 年前

    问题1的答案是:这是因为断路器decorator,因为它的逻辑是在模块导入期间执行的,并且它调用了decorated函数。检查下面几行

    ...
    try:
        func() # <-- here
    except Exception as ex:
        print(ex)
        ...
    

    实现decorators的方法是返回一个包装函数,它包含业务逻辑:

    from functools import wraps
    
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            ... your logic here ...
        return wrapper
    

    问题2的答案来自上一个问题。

        2
  •  1
  •   Patrick Artner    6 年前

    Answers to almost all questions you never asked about decorators

    装饰某物的函数应该返回它自己所做的功能-而不是 所有的东西-你返回的不是一个“函数指针”,而是一个隐式的 None 从你的除臭剂(含蓄地说,你什么也不回)。这个 没有 然后叫…

    如何修复:

    def circuitbreaker(func):
        def the_works():
            global count
            global open_time , state
            print("circuit status "+ status.get(state))
            # .. all your other code ...
        return the_works
    

    for _ in range(5): 
        generic_func()
    

    固定输出 :

    circuit status closed
    hello
    random number = 3
    Yalla!
    circuit status closed
    hello
    random number = 3
    Yalla!
    circuit status closed
    hello
    random number = 0
    Yalla!
    opening circuit breaker
    circuit status  open
    circuit opened
    circuit status  open
    circuit opened
    
        3
  •  1
  •   hellokangning    6 年前
    1. decorators在decorated函数定义之后立即运行,这通常是在导入时。在装潢师 circuitbreaker 你打电话 generic_func 已经。

    Here 是fluent python的一个例子:

    registry = []
    
    def register(func):
        print('running register(%s)' % func)
        registry.append(func)
        return func
    
    @register
    def f1():
        print('running f1()')
    
    @register
    def f2():
        print('running f2()')
    
    def f3():
        print('running f3()')
    
    def main():
        print('registry ->', registry)
        f1()
        f2()
        f3()
    
    if __name__ == '__main__':
        main()
    

    输出是

    running register(<function f1 at 0x1055ae378>)
    running register(<function f2 at 0x1055ae400>)
    registry -> [<function f1 at 0x1055ae378>, <function f2 at 0x1055ae400>]
    running f1()
    running f2()
    
    1. 这是你想要的吗: How do I catch an exception in a decorator but allow the caller to catch it as well?