Python装饰器

时间:2018-12-13 07:05:34

标签: python python-decorators

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)当我取消注释main函数中的注释部分时。我收到以下错误。如何正确调用此泛型函数。 我的动机是实现一个断路器,该断路器在调用函数中出现某种错误或异常时闭合。我可以直接使用:-     断路器(调用函数),但我想使用装饰器

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

问题在于装饰器应该返回一个函数对象,并且应该在函数内部具有相关的逻辑,然后返回该函数,否则它不返回任何对象

3 个答案:

答案 0 :(得分:2)

问题1的答案:这是因为断路器装饰器,因为其逻辑是在模块导入期间执行的,并调用了装饰的功能。检查以下几行

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

实现装饰器的方法是返回一个包装函数,其中包含业务逻辑:

from functools import wraps

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

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

答案 1 :(得分:1)

Answers to almost all questions you never asked about decorators

装饰某物的函数应该返回其自身功能的函数-不是所有事情-您不是在返回“ functionpointer”,而是返回一个隐式None您的灭杀者(隐含的是您什么也不返回)。然后将此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

答案 2 :(得分:1)

  1. 装饰器在定义装饰函数后立即运行,通常在导入时运行。在修饰器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?