Decorator 정리 및 예시

1. decorator 기본구성

  • A: enclosing func
  • B: nested func
  • C: func as arg

2. 작동

  • Call C
  • Pass C into A as arg
  • A return B
  • B do something using C

3. code example

  • func basic

    1
    2
    3
    4
    5
    def plus_one(num):
    return num + 1

    plus_one(5)
    >> 6
  • func call another func

    1
    2
    3
    4
    5
    6
    7
    8
    def plus_one(num):
    def add_one(num):
    return num + 1

    result = add_one(num)
    return result
    plus_one(1)
    >> 2
  • func as arg

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def plus_one(num):
    return num + 1

    def func_call(func):
    num_to_add = 5
    return func(num_to_add)

    func_call(plus_one)
    >> 6
  • func nesting another func

    1
    2
    3
    4
    5
    6
    7
    def hello_func():
    def say_hi():
    return "Hi"
    return say_hi()

    hello_func()
    >> 'Hi'
  • nested function access the outer scope of the enclosing func

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # a critical concept in decorators:
    # nested function access the outer scope of the enclosing func
    def print_msg(msg):
    def msg_sender():
    print(msg)
    msg_sender()

    print_msg('yes')
    >> yes

step1

  • decorator without args
1
2
3
4
5
6
7
8
9
10
11
12
# Nested func use outer func's variable
# which is func as agrs
# Enclosing func
def uppercase_decorator(func):
def wrapper():
return func().upper()
return wrapper

@uppercase_decorator
def say():
return 'hello there'
say()
'HELLO THERE'

step2

  • decorator which accept args
1
2
3
4
5
def dec_with_args(func):
def nested_accept_args(arg1, arg2):
print('ars: {}, {}'.format(arg1, arg2))
func(arg1, arg2)
return nested_accept_args
1
2
3
4
5
@dec_with_args
def cities(first, second):
print('cities: {}, {}'.format(first, second))

cities('sun', 'moon')
ars: sun, moon
cities: sun, moon

step3

  • decorator which accept as many args as user would like
1
2
3
4
5
6
7
8
9
10
11
12
13
def dec_pass_arbitrary_args(func):
def wrapper(*args, **kwargs):
print('the positional args are', args)
print('the keword args are', kwargs)
func(*args)
return wrapper

# with positional args
@dec_pass_arbitrary_args
def func_with_args(a, b, c):
print(a, b, c)

func_with_args(1,2,3)
the positional args are (1, 2, 3)
the keword args are {}
1 2 3
1
2
3
4
5
@dec_pass_arbitrary_args
def func_with_kwargs():
print('this has keyword args')

func_with_kwargs(name='Roy', age='12')
the positional args are ()
the keword args are {'name': 'Roy', 'age': '12'}
this has keyword args

step4

  • dec within wrapper passing dec_args
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def dec_wrapper(*dec_args):
def dec(func):
"decorator we code above"

def wrapper(*func_args):
print("dec positional args: ", dec_args)
print("func positional args: ", func_args)
return func(*func_args)

return wrapper

return dec

@dec_wrapper('dec1', 'dec2')
def func1(*args):
print('this is from func1', args)
func1('func1', 'func2')
dec positional args:  ('dec1', 'dec2')
func positional args:  ('func1', 'func2')
this is from func1 ('func1', 'func2')

step5

  • decorator which measure the execution time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
def timeit(func):
def wrapper(*args, **kwargs):
print('strat timeit')

ts = time.time()
result = func(*args)
te = time.time()

print(func.__name__, te-ts)
return result
return wrapper

@timeit
def multiply_nums(*num):
print('start multiply func')
i = 1
for j in num:
i *= j
return i

res = multiply_nums(1,2,3)
print(res)
strat timeit
start multiply func
multiply_nums 4.982948303222656e-05
6
< !-- add by yurixu 替换Google的jquery并且添加判断逻辑 -->