python 装饰器,高阶函数,函数闭包

https://www.cnblogs.com/linhaifeng/articles/7532497.html
https://www.cnblogs.com/linhaifeng/articles/6140395.html

一.装饰器
1.本质就是函数/类,用于修饰其他函数(添加附加功能)
2.原则:不修改被修饰函数的源代码/调用方式(开放封闭原则:对扩展开放,对修改封闭)(修改后后果未知)
3.知识储备:装饰器=高阶函数+函数嵌套+函数闭包
4.语法:被装饰函数的正上方,单独一行

import time

def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()    
        res=func(*args,**kwargs)
        stop_time=time.time()
        print("函数运行时间是%s"%(stop_time-start_time)) 
        return res
    return wrapper
                                        
@timmer
def cal(li):
    res=0
    for i in li:
        time.sleep(0.1)
        res+=i        
    return res

a=cal(range(20))
print(a)
#结果为:函数运行时间是2.0001144409179688
#            190

5.基本实现:

import time
#装饰器框架
def timmer(func):
    def wrapper(name,age):
        #print(func)
        start_time=time.time()
        res=func(name,age)   #在运行test
        stop_time=time.time()
        print("运行时间是%s"%(stop_time-start_time))
        return res
    return wrapper        

def test(name,age):
    print("我是%s,今年%s岁"%(name,age))
    return "test的返回值"

test=timmer(test)   #返回的是wrapper的地址   
test("alex",18)   #实际运行的是timmer的返回值wrapper  

6.使用可变长参数与语法糖:
语法糖:@timmer相当于test=timmer(test),位于要修饰的函数前边,单独占一行

def timmer(func):
    def wrapper(*args,**kwargs):
        #print(func)
        start_time=time.time()
        res=func(*args,**kwargs)   #在运行test
        stop_time=time.time()
        print("运行时间是%s"%(stop_time-start_time))
        return res
    return wrapper               

@timmer
def test1(name,age):
    print("我是%s,今年%s岁"%(name,age))
    return "test的返回值"

@timmer
def test2(name,age,gender):
    print("我是%s,今年%s岁,是%s性"%(name,age,gender))
    return "test的返回值"

test1("alex",18)
test2("alex",18,"男")

7.使用:

#无参装饰器=函数嵌套+高阶函数:
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print('from foo')
foo()
#有参装饰器:
def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')
def foo(name):
    print(name)

foo('egon')

8.超时装饰器

import sys,threading,time

class KThread(threading.Thread):
    """A subclass of threading.Thread, with a kill()
    method.
    Come from:
    Kill a thread in Python:
    http://mail.python.org/pipermail/python-list/2004-May/260937.html"""
    def __init__(self, *args, **kwargs):
        threading.Thread.__init__(self, *args, **kwargs)
        self.killed = False
    def start(self):
        """Start the thread."""
        self.__run_backup = self.run
        self.run = self.__run      # Force the Thread to install our trace.
        threading.Thread.start(self)
    def __run(self):
        """Hacked run function, which installs the trace."""
        sys.settrace(self.globaltrace)
        self.__run_backup()
        self.run = self.__run_backup
    def globaltrace(self, frame, why, arg):
        if why == 'call':
          return self.localtrace
        else:
          return None
    def localtrace(self, frame, why, arg):
        if self.killed:
          if why == 'line':
            raise SystemExit()
        return self.localtrace
    def kill(self):
        self.killed = True
                
class Timeout(Exception):
    """function run timeout"""

def timeout(seconds):
    """超时装饰器,指定超时时间
    若被装饰的方法在指定的时间内未返回,则抛出Timeout异常"""
    def timeout_decorator(func):
        """真正的装饰器"""
        def _new_func(oldfunc, result, oldfunc_args, oldfunc_kwargs):
            result.append(oldfunc(*oldfunc_args, **oldfunc_kwargs))
        def _(*args, **kwargs):
            result = []
            new_kwargs = { # create new args for _new_func, because we want to get the func return val to result list
            'oldfunc': func,'result': result, 'oldfunc_args': args,'oldfunc_kwargs': kwargs}
            thd = KThread(target=_new_func, args=(), kwargs=new_kwargs)
            thd.start()
            thd.join(seconds)
            alive = thd.isAlive()
            thd.kill() # kill the child thread
            if alive:
                raise Timeout(u'function run too long, timeout %d seconds.' % seconds)
            else:
                return result[0]
        _.__name__ = func.__name__
        _.__doc__ = func.__doc__
        return _
    return timeout_decorator

@timeout(5)
def method_timeout(seconds, text):
    print('start', seconds, text)
    time.sleep(seconds)
    print('finish', seconds, text)
    return seconds

method_timeout(6,'asdfasdfasdfas')

9.wraps:

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper

@deco
def index():
    '''哈哈哈哈'''
    print('from index')

print(index.__doc__)

10.叠加多个装饰器:
加载顺序(outter函数的调用顺序):自下而上
执行顺序(wrapper函数的执行顺序):自上而下

def outter1(func1): #func1=wrapper2的内存地址
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): #func2=wrapper3的内存地址
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def outter3(func3): # func3=最原始的那个index的内存地址
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3=func3(*args,**kwargs)
        return res3
    return wrapper3

@outter1 # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2 # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3 # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
def index():
    print('from index')

print('===')
index()

python 装饰器,高阶函数,函数闭包_第1张图片
二.高阶函数的使用
参数为函数-----可不修改源代码,会改变被修饰函数调用方式:

import time
def foo():
    print("a")

def test(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print("函数运行时间是%s"%(stop_time-start_time))

test(foo)

返回值是函数-----可不更改调用方式,会修改源代码:

import time

def foo():
    print("a")

def test(func):
    return func

foo=test(foo)
foo()

二者结合-----foo()运行了2遍:

import time

def foo():
    print("a")

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()    
    print("函数运行时间是%s"%(stop_time-start_time))
    return func

foo=timmer(foo)
foo()

三.函数闭包
1.闭包:在一个作用域里放入定义

一个闭包内是一个作用域

2.意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

3.应用:延迟计算(原来是传参,现在是包起来)

from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()
    return get

baidu=index('http://www.baidu.com')
print(baidu().decode('utf-8'))

四.解压序列:

l=[1,23,4,54,3,54,2,37,19,12,3,45]
a,*_,b=l   #a为1,b为45,_为[23,4,54,3,54,2,37,19,12,3]
#_也可换为任何非空字符
c,d,*_,e,f=l   #c为1,d为23,e为3,f为45
*_,g=l   #g为45

你可能感兴趣的:(Python)