[Note] Advanced python decorator (decorator) (emphasis)

[Note] Advanced python decorator (focus)

table of Contents

1. Introduction decorator

1.1 The introduction of the code

1.2. The demand (by demand gradually understand)

1.3. The implementation process decorators (important)

2. decorator (decorator) role

Example 3. decorator

3.1 for non-return value, no decorative function parameters

3.2. There are a function parameters, no return value decorated

3.3. Decorator with a plurality of the same functions for decoration

3.4. When will begin decorating decorator? !

3.5. For variable length function arguments are decorated!

3.6. To return to the values ​​of variable length parameter function decoration (important)

4. Decorative plurality decorative function on the same

A plurality of decorator same function for decorative applications Demo

The decorator with parameters, on the basis of an original decoration on the external variable set

6. class decorator (Learn)


1. Introduction decorator

Decorator is a function of program development often used with good decorator, development efficiency even more powerful, it is also necessary Python interview questions.

1.1 The introduction of the code

#### 第一段 ####
def foo():
    print('foo')

foo  # 表示是函数,变量名指向了函数
foo()  # 表示执行foo函数

#### 第二段 ####
def foo():
    print('foo')

foo = lambda x: x + 1  # lambda 匿名函数,默认返回值是表达式的结果

foo()  # 执行lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数

In python, all method names, function names, variable names and class names are usually not allowed the same, python, regarded them as a variable name to be treated.

Therefore, the above code, the function name is just a variable, but point to a function definition only, so can () function call by name. If the function name = xxx is modified, then when that function is not before when executing the function name (), called up .

 

1.2. The demand (by demand gradually understand)

N startups have business units, departments responsible for providing the basic functionality of the underlying platform, such as: database operations, redis calls, monitor API functions. When using the basic business functions, simply call function can be provided by the underlying platform. as follows:

############### 基础平台提供的功能如下 ###############

def f1():
    print('f1')

def f2():
    print('f2')

def f3():
    print('f3')

def f4():
    print('f4')

############### 业务部门A 调用基础平台提供的功能 ###############

f1()
f2()
f3()
f4()

############### 业务部门B 调用基础平台提供的功能 ###############

f1()
f2()
f3()
f4()

The company orderly conduct, however, before the underlying platform developers do not focus on problems related to verification at time of writing code, namely: functionality provided by the underlying platform can be used by anyone. Now we need the basic platform for all of the functions of reconstruction , add authentication mechanisms to provide all the capabilities of the platform, namely: former executive function, to be verified.

 

(Scheme 1) boss to work to Low B, he is doing:

Negotiate with each business unit, each business unit to write code before calling the function of the underlying platform to verify. Ah, so that the base platform do not need to make any changes to the. Cool, there is plenty of time to soak sister ...

Low B was fired the same day ...

 

(Option 2: a function related functions one by one modification ) boss to work to Low BB, he is doing:

############### 基础平台提供的功能如下 ############### 

def f1():
    # 验证1
    # 验证2
    # 验证3
    print('f1')

def f2():
    # 验证1
    # 验证2
    # 验证3
    print('f2')

def f3():
    # 验证1
    # 验证2
    # 验证3
    print('f3')

def f4():
    # 验证1
    # 验证2
    # 验证3
    print('f4')

############### 业务部门不变 ############### 
### 业务部门A 调用基础平台提供的功能### 

f1()
f2()
f3()
f4()

### 业务部门B 调用基础平台提供的功能 ### 

f1()
f2()
f3()
f4()

( Code reuse much not ) after a week Low BB was fired ...

 

( Scenario 3 : Define a function used to call) boss to work to Low BBB, he is doing:

Only to reconstruct the code base platform, other business units without any modifications

############### 基础平台提供的功能如下 ############### 

def check_login():
    # 验证1
    # 验证2
    # 验证3
    pass


def f1():

    check_login()

    print('f1')

def f2():

    check_login()

    print('f2')

def f3():

    check_login()

    print('f3')

def f4():

    check_login()

    print('f4')

Boss looked achieved under the Low BBB, mouth leak a comforting smile a trace of earnestness with Low BBB chatted a day:

Boss said:

Write code to follow open closed principle , although this principle is used in object-oriented development, but also applies to functional programming, in simple terms, it specified function code has been implemented can not be modified, but can be extended , namely:

  • Closed : function code block is realized, can not be modified
  • Open : For extension developers

If the Open Closed Principle applied in the above-mentioned requirements, then they are not allowed to modify the code inside the function f1, f2, f3, f4 of the boss gave a Low BBB implementation:

( Scheme 4 : with decorator)

def w1(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        func()
    return inner

@w1
def f1():
    print('f1')
@w1
def f2():
    print('f2')
@w1
def f3():
    print('f3')
@w1
def f4():
    print('f4')

For the above code, the code is only the underlying platform be modified, can be achieved are carried out before anyone else calling the function f1 f2 f3 f4] [verification operations, and other business units do not need to do anything.

 

This code of internal execution principles :

The following party code as an example:

def set_func(func):
	def call_func():
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func()
	return call_func

@set_func  
def test1():
	print("-----test1----")

test1()


#输出:
#---这是权限验证1----
#---这是权限验证2----
#-----test1----
  • If the need to modify the function of the function A (eg: to increase the part before the function call codes), may be defined outside of a function A closure , in front of the write function of A @ closure external function name  , this will first perform @ function of  . Add functionality can be achieved in the overall function does not modify the original premise.
  • As above, before adding @set_func test1 add function can be achieved "authentication."

 

1.3. The implementation process decorators (important)

def set_func(func):
	def call_func():
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func()
	return call_func


# 代码段1----------
@set_func  # 等价于test1 = set_func(test1) 
def test1():
	print("-----test1----")
test1()  # 可通俗的看做调用了call_func


# 代码段2------------
# def test1():
# 	print("-----test1----")
# ret = set_func(test1)
# ret()


# 代码段3-----------
# def test1():
# 	print("-----test1----")
# test1 = set_func(test1) 
# test1()

Run output code segments 2,3 are the same:

---这是权限验证1----
---这是权限验证2----
-----test1----

analysis:

  • Look at the  code segment 2 : realized by closure feature adds two added outputs.
  • Look at  the code segment 1 : prepend function test1 defined @set_func , equivalent to set_func = test1 (test1) . As used herein, the decorator , and an entire code segment 3 is exactly equivalent to the code segment.
  • 3 code snippet :
    1. In python, all method names, function names, variable names and class names are usually the same is not allowed.
    2. However, code segments 3, after the function test1 definitions, statements test1 = set_func (test1) and defines a variable used to keep test1 set_func (test1) results returned;
    3. set_func (test1) as a function test1 reference parameter to the function set_func, and defined functions call_func set_func the return value as a function  (in this case call_func pointing to the original function func test1, func () function call i.e. test1);
    4. At this time set_func (test1) points to the return value of the function call_func, (including the added function code and the function code the original test1) , and then define the variable test1  receives its return value, which is, can be performed colloquially test1 (on) It calls call_func .
    5. In this way, clever realized added to the function test1 function, but also with variable test1 re-code function to add points. Compared to Listing 1 , still use test1 to call when calling .
    6. 3 used in the second segment of code that is a code segment  implementation decorator .

Code segments 2 and 3 decorators snippet advantages :

  1. Without modifying the internal functions of the original plus-function code;
  2. Still with the original name of the function to call when the call without modification.
  3. That can be done in the case of constant transfer function, so expanding its functions .

Note that the decoration can only add code or function before or after the function.

 

2. decorator (decorator) role

  1. The introduction of the log
  2. Function execution time statistics
  3. Before performing the function preparatory process
  4. After executing function cleanup function
  5. Check permissions and other scenes
  6. Cache

demo: run-time statistical functions

import time


def set_func(func):
	def call_func():
		start_time = time.time()
		func()
		stop_time = time.time()
		print("alltimeis %f" % (stop_time - start_time))
	return call_func


@set_func  # 等价于test1 = set_func(test1) 
def test1():
	print("-----test1----")
	for i in range(10000):
		pass
test1()

 

Example 3. decorator

3.1 for non-return value, no decorative function parameters

Reference 1.3 demo can be.

 

3.2. There are a function parameters, no return value decorated

def set_func(func):
	def call_func(a):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func(a)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
	print("-----test1----%d" % num)

test1(100)  # 可通俗的看做调用了call_func
# test1(200)

test1 (100) may be regarded as the popular called call_func, 100 pass a, a then pass func, func argument i.e., the original function test1.

 

3.3. Decorator with a plurality of the same functions for decoration

def set_func(func):
	def call_func(a):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func(a)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
	print("-----test1----%d" % num)


@set_func  # 相当于 test2 = set_func(test2)
def test2(num):
	print("-----test2----%d" % num)


test1(100)  # 可通俗的看做调用了call_func(100)
test2(200)

  • A function equivalent to creating a decorative closure.

 

3.4. When will begin decorating decorator? !

def set_func(func):
	print("---开始进行装饰")
	def call_func(a):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		func(a)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num):
	print("-----test1----%d" % num)


# 装饰器在调用函数之前,已经被python解释器执行了,所以要牢记 当调用函数之前 其实已经装饰好了,尽管调用就可以了
# test1(100)



Above demo does not call the test1 function to perform, but will output: --- start decoration

  • Visible : Just write on the front function definition  @ closure of the outer function name begins decorated, rather than decorative function when the execution start decoration .
  • That will be executed as long as the encounter decorator, decorator before calling the function ,, has been performed python interpreter.
  • So when you want to keep in mind before calling the function it is already decorated well, despite calling it

 

3.5. For variable length function arguments are decorated!

def set_func(func):
	print("---开始进行装饰")
	def call_func(*args, **kwargs):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		# func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
		func(*args, **kwargs)  # 做实参时写上*或**会拆包(写args相当与直接传一个元祖或字典参数)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
	print("-----test1----%d" % num)  # num替换%d 
	print("-----test1----" , args)  # 先打印逗号前的部分,再打印逗号后的args元祖
	print("-----test1----" , kwargs)


test1(100)
test1(100, 200)
test1(100, 200, 300, mm=100)

In fact, when there is for 0 and above decorative function, write directly to variable length parameters, we can achieve a common effect . Note again re-transmission of unpacking the parameters passed.

Note: * args, ** kwargs parameters passed as an argument to another when other parameters, write * or ** will be unpacking. The pass args or kwargs directly comparable Ganso or pass a dictionary parameter.

 

3.6. To return to the values ​​of variable length parameter function decoration (important)

The Demo decorator for variable length parameters and return values of the function are the presence or absence general, a universal decorator .

def set_func(func):
	print("---开始进行装饰")
	def call_func(*args, **kwargs):
		print("---这是权限验证1----")
		print("---这是权限验证2----")
		# func(args, kwargs)  # 不行,相当于传递了2个参数 :1个元组,1个字典
		return func(*args, **kwargs)  # 做实参时写上*或**会拆包(写args相当与直接传一个元祖或字典参数)
	return call_func


@set_func  # 相当于 test1 = set_func(test1)
def test1(num, *args, **kwargs):
	print("-----test1----%d" % num)
	print("-----test1----" , args)
	print("-----test1----" , kwargs)
	return "ok"


@set_func
def test2():
	pass

ret = test1(100)
print(ret)

ret = test2()
print(ret)

ret = test1 (100) of the closure point test1 function call_func.

test1 (100) call the procedure:

test1  --- call ---> 

call_func --- FUNC (corresponding to the argument test1) will call ---> 

test1 --- ok to return test1 ---> 

call_func --- return ok test1 returned and assigned to --->

Variable ret

Seen from the function test2, no return value of a function of its decorator to write return has no effect, because the returns None.

 

4. Decorative plurality decorative function on the same

def add_privilege_1(func):
	print("---开始进行装饰权限1的功能---")
	def call_func(*args, **kwargs):
		print("---这是权限1验证----")
		return func(*args, **kwargs)
	return call_func


def add_privilege_2(func):
	print("---开始进行装饰权限2的功能---")
	def call_func(*args, **kwargs):
		print("---这是权限2验证----")
		return func(*args, **kwargs)
	return call_func


@add_privilege_1  # 等价于 test1 = add_privilege_1(test1)
@add_privilege_2  # 等价于 test1 = add_privilege_2(test1)
def test1():
	print("------test1------")


test1()

Output:

--- began to be decorated permissions feature 2 ---
--- began to be decorated permissions feature 1 ---
--- This is a privilege verification ----
--- ---- This is Priv2 verification
------ test1 ------
 

Output seen by the analysis:

  • When a decorative function with a plurality of decorators, following the first load, installed after the above, similar to the principle of strip .
    • For example, demo @ add_privilege_2 from the function test1 closer to decorate. @ Add_privilege_2 function function test1 from the second into the second decoration.
  • @ add_privilege_2 equivalent test1 = add_privilege_2 ( test1 ) , equivalent to add_privilege_1 @ test1 = add_privilege_1 ( test1 ) (Note: at this time as a parameter test1  points to new points after performing the decorator @ add_privilege_2 test1 , it is no longer pointing to the original test1 function ...), after the decorative finish, test1 points to the last decorative func.
  • Therefore, when performing test1 (), to perform the write in the above, after executing the following writing, and decoration in reverse order .

 

Multiple decorators of significance : When an original functions need to add more features, you can use multiple decorators to add functionality and ensure a decorator function .

 

A plurality of decorator same function for decorative applications Demo

Decorator with the value returned by the original function plus <h1> </ h1> tag and the <td> </ td> tags.

def set_func_1(func):
	def call_func():
		# "<h1>haha</h1>"
		return "<h1>" + func() + "</h1>"
	return call_func

def set_func_2(func):
	def call_func():
		return "<td>" + func() + "</td>"
	return call_func


@set_func_1
@set_func_2
def get_str():
	return "haha"

print(get_str())

输出: <h1><td>haha</td></h1>

Output results again verify the decorator's execution order (Note: decorative opposite order).

 

The decorator with parameters, on the basis of an original decoration on the external variable set

Examples and comments are as follows:

from time import ctime, sleep

def timefun_arg(pre="hello"):
    def timefun(func):
        def wrapped_func():
            print("%s called at %s %s" % (func.__name__, ctime(), pre))
            return func()
        return wrapped_func
    return timefun

# 下面的装饰过程
# 1. 调用timefun_arg("test")
# 2. 将步骤1得到的返回值,即time_fun返回, 然后time_fun(foo)
# 3. 将time_fun(foo)的结果返回,即wrapped_func
# 4. 让foo = wrapped_fun,即foo现在指向wrapped_func

@timefun_arg("test")  # 等价于foo = timefun_arg("test")(foo)
def foo():
    print("I am foo")

foo()
sleep(2)
foo()

# 执行时可以理解为:foo() == timefun_arg("test")(foo)() == time_fun(foo)() == wrapped_func()

Output:

foo called at Fri Feb 28 14:10:00 2020 test
I am foo
foo called at Fri Feb 28 14:10:02 2020 test
I am foo

 

6. class decorator (Learn)

Decorator is actually a function interface constraints , it must accept a callable object as a parameter, and then returns a callable objects. In Python objects are usually callable function, but there are exceptions. As long as an object overrides the  __call__() method, the object is callable in.

# def set_func_1(func):
# 	def call_func():
# 		# "<h1>haha</h1>"
# 		return "<h1>" + func() + "</h1>"
# 	return call_func


class Test(object):
	def __init__(self, func):
		self.func = func

	def __call__(self):
		print("这里是装饰器添加的功能.....")
		return self.func()


@Test  # 相当于get_str = Test(get_str)  ,等号右边类名()意味着创建了一个实例对象(get_str再指向实例对象),get_str传给了类的__init__方法
def get_str():
	return "haha"

print(get_str())  # 实例对象() 会调用__call__方法

Output:

Here is the decorator added functionality .....
haha

 

 

-----end-----

Published 50 original articles · won praise 10 · views 6604

Guess you like

Origin blog.csdn.net/qq_23996069/article/details/104535477