The decorator in Python is a hurdle for you to enter Python. It is there whether you cross it or not. The concept of decorators in Python often confuses people, so today I will analyze the decorators in Python
1. Scope
In python, scope is divided into two types: global scope and local scope.
The global scope is the variable and function name defined at the file level. The local scope is inside the defining function.
Regarding scope, I need to understand two points: a. Locally defined variables cannot be accessed globally b. Globally defined variables can be accessed locally, but globally defined variables cannot be modified (of course there are methods Can be modified)
Let’s take a look at the following example:
x = 1 def funx(): x = 10 print(x) # 打印出10 funx() print(x) # 打印出1
If there is no defined variable x locally, then the function will Start searching for The file is referenced anywhere, but the modification can only be performed globally; if the required variable is not found locally, it will be searched externally, and an error will be reported if it is not found.
2. Advanced functions
aThe function name can be used as a value
x = 1 def funx(): print(x) # 打印出1 funx() print(x) # 打印出1 x = 1 def funx(): def func1(): print(x) # 打印出1 func1() funx() print(x) # 打印出1
b.The function name can be used as the return value
def delete(ps): import os filename = ps[-1] delelemetns = ps[1] with open(filename, encoding='utf-8') as f_read,\ open('tmp.txt', 'w', encoding='utf-8') as f_write: for line in iter(f_read.readline, ''): if line != '\n': # 处理非空行 if delelemetns in line: line = line.replace(delelemetns,'') f_write.write(line) os.remove(filename) os.rename('tmp.txt',filename) def add(ps): filename = ps[-1] addelemetns = ps[1] with open(filename, 'a', encoding='utf-8') as fp: fp.write("\n", addelemetns) def modify(ps): import os filename = ps[-1] modify_elemetns = ps[1] with open(filename, encoding='utf-8') as f_read, \ open('tmp.txt', 'w', encoding='utf-8') as f_write: for line in iter(f_read.readline, ''): if line != '\n': # 处理非空行 if modify_elemetns in line: line = line.replace(modify_elemetns, '') f_write.write(line) os.remove(filename) os.rename('tmp.txt', filename) def search(cmd): filename = cmd[-1] pattern = cmd[1] with open(filename, 'r', encoding="utf-8") as f: for line in f: if pattern in line: print(line, end="") else: print("没有找到") dic_func ={'delete': delete, 'add': add, 'modify': modify, 'search': search} while True: inp = input("请输入您要进行的操作:").strip() if not inp: continue cmd_1 = inp.split() cmd = cmd_1[0] if cmd in dic_func: dic_func[cmd](cmd_1) else: print("Error")
c.. The function name can be used as a parameter
def outer(): def inner(): pass return inner s = outer() print(s) ######输出结果为####### <function outer.<locals>.inner at 0x000000D22D8AB8C8>
Therefore, if one of the above two conditions is met, it can be called an advanced function.
3. Closure function
The following illustrates the closure function through some examples:
Example 1: The following only defines a function inside the function, but it is not a closure function.def index(): print("index func") def outer(index): s = index s() outer(index) ######输出结果######### index func
Example 2: The following defines a function inside the function and also references an external variable x. Is this a closure function? Answer: No
##
def outer(): def inner(): print("inner func excuted") inner() # 调用执行inner()函数 print("outer func excuted") outer() # 调用执行outer函数 ####输出结果为########## inner func excuted outer func excuted
x = 1 def outer(): def inner(): print("x=%s" %x) # 引用了一个非inner函数内部的变量 print("inner func excuted") inner() # 执行inner函数 print("outer func excuted") outer() #####输出结果######## x=1 inner func excuted outer func excuted
def outer(): x = 1 def inner(): print("x=%s" %x) print("inner func excuted") inner() print("outer func excuted") outer() #####输出结果######### x=1 inner func excuted outer func excuted
def outer(): x = 1 def inner(): print("x=%s" %x) print("inner func excuted") print("outer func excuted") return inner # 返回内部函数名 outer()
The results show that inside the inner, references Two external local variables. If a non-local variable is referenced, then the output here is None.
Characteristics of the closure function:
1. Has its own scope 2. Delayed calculation
def outer(): x = 1 y = 2 def inner(): print("x= %s" %x) print("y= %s" %y) print(inner.closure) return inner outer() ######输出结果####### (<cell at 0x000000DF9EA965B8: int object at 0x000000006FC2B440>, <cell at 0x000000DF9EA965E8: int object at 0x000000006FC2B460>)
Some people may say that this does not meet the conditions of the closure function! I did not reference non-global external variables. In fact, this is not the case. As we said before, as long as the variables inside the function belong to the function. Then I am at index(url), this url also belongs inside the function, but we have omitted one step, so the above function is also a closure function.
4. DecoratorFeatures: 1. Does not modify the calling method of the decorated function 2. Does not modify the source code of the decorated function
a. Parameterless decorator There are the following examples, We need to calculate the execution time of the code.import time, random def index(): time.sleep(random.randrange(1, 5)) print("welcome to index page")
根据装饰器的特点,我们不能对index()进行任何修改,而且调用方式也不能变。这时候,我们就可以使用装饰器来完成如上功能.
import time, random def outer(func): # 将index的地址传递给func def inner(): start_time = time.time() func() # fun = index 即func保存了外部index函数的地址 end_time = time.time() print("运行时间为%s"%(end_time - start_time)) return inner # 返回inner的地址 def index(): time.sleep(random.randrange(1, 5)) print("welcome to index page") index = outer(index) # 这里返回的是inner的地址,并重新赋值给index index()
但是,有些情况,被装饰的函数需要传递参数进去,有些函数又不需要参数,那么如何来处理这种变参数函数呢?下面来看看有参数装饰器的使用情况.
b.有参装饰器
def outer(func): # 将index的地址传递给func def inner(*args, **kwargs): start_time = time.time() func(*args, **kwargs) # fun = index 即func保存了外部index函数的地址 end_time = time.time() print("运行时间为%s"%(end_time - start_time)) return inner # 返回inner的地址
下面来说说一些其他情况的实例。
如果被装饰的函数有返回值
def timmer(func): def wrapper(*args,**kwargs): start_time = time.time() res=func(*args,**kwargs) #res来接收home函数的返回值 stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper def home(name): time.sleep(random.randrange(1,3)) print('welecome to %s HOME page' %name) return 123123123123123123123123123123123123123123
这里补充一点,加入我们要执行被装饰后的函数,那么应该是如下调用方式:
home = timmer(home) # 等式右边返回的是wrapper的内存地址,再将其赋值给home,这里的home不在是原来的的那个函数,而是被装饰以后的函数了。像home = timmer(home)这样的写法,python给我们提供了一个便捷的方式------语法糖@.以后我们再要在被装饰的函数之前写上@timmer,它的效果就和home = timmer(home)是一样的。
如果一个函数被多个装饰器装饰,那么执行顺序是怎样的。
import time import random def timmer(func): def wrapper(): start_time = time.time() func() stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return wrapper def auth(func): def deco(): name=input('name: ') password=input('password: ') if name == 'egon' and password == '123': print('login successful') func() #wrapper() else: print('login err') return deco @auth # index = auth(timmer(index)) @timmer # index = timmer(index) def index(): time.sleep(3) print('welecome to index page') index()
实验结果表明,多个装饰器装饰一个函数,其执行顺序是从下往上。
关于装饰器,还有一些高级用法,有兴趣的可以自己研究研究。
The above is the detailed content of Detailed example tutorial of python decorator. For more information, please follow other related articles on the PHP Chinese website!