简体   繁体   中英

Issue creating decorator in Python3

Can anyone let me know what mistake i'm making.

Decorator

import time

def f1(f):

    a = time.time()
    f()
    b = time.time()
    c = b-a
    print("time required is", c)
@f1

def f3(f2):

    n = []
    for i in range(1000):
        n.append(i)
    print(sum(n), "for F3")
    f2()

@f3

def f4():

    n = []
    for i in range(1000):
       n.append(i)
    print(sum(n), "for F4")

f4

o/p:

Traceback (most recent call last):

File "C:/test.py", line 13, in <module>

@f1

File "C:/test.py", line 7, in f1

f()

TypeError: f3() missing 1 required positional argument: 'f2'

Process finished with exit code 1

looking to achieve something like this:

def decorator_with_args(decorator_to_enhance):

def decorator_maker(*args, **kwargs):

    def decorator_wrapper(func):

        return decorator_to_enhance(func, *args, **kwargs)

    return decorator_wrapper

return decorator_maker

@decorator_with_args

def decorated_decorator(func, *args, **kwargs):

def wrapper(function_arg1, function_arg2):

    print("Decorated with {0} {1}".format(args, kwargs))

    return func(function_arg1, function_arg2)

return wrapper

@decorated_decorator(42, 404, 1024)

def decorated_function(function_arg1, function_arg2):

print("Hello {0} {1}".format(function_arg1, function_arg2))

decorated_function("Universe and", "everything")

While you can wrap and function in another single function that does not return any callable object, bear in mind that the wrapped function is no longer callable. Thus, when timing objects that do not require reusability of the original object, then your current code works:

import time
def timeit(f):
  c = time.time()
  _ = f()
  c2 = time.time()
  print(f"'{f.__name__}' took {c2-c}s")

@timeit
def f2():
  return sum(range(1000))

Output (without calling f2 ):

'f2' took 8.988380432128906e-05s

However, if attempting to call f2 :

_ = f2()

Traceback (most recent call last): File "", line 1, in TypeError: 'NoneType' object is not callable

To prevent the above error, create a wrapper function inside the decorating function:

def timeit(f):
 def wrapper(*args, **kwargs):
    c = time.time()
    _result = f(*args, **kwargs)
    c2 = time.time()
    print(f"'{f.__name__}' took {c2-c}s")
    return _result
 return wrapper

@timeit
def f2():
  return sum(range(1000))

f2 will not be timed until it is called, triggering wrapper :

print(f2())

Output:

'f2' took 3.981590270996094e-05s
499500

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM