• Python3 函数进阶1


    闭包函数

    什么是闭包函数

    闭包函数本质上就是函数嵌套和高阶函数

    闭包函数的满足条件:

    • 必须嵌套函数
    • 内嵌函数必须引用外部函数的变量
    • 外部函数必须返回内嵌函数的函数对象(函数名)
    # outer 是一个闭包函数
    def outer():
        x = 1
        def inner():
            print(X)  # 内嵌函数引用了外部函数里的变量
        return inner  # 外部函数返回内嵌函数的函数对象
    
    f1 = outer()
    f1()
    
    

    闭包函数的作用

    闭包函数不仅返回了内嵌函数的函数对象, 还在其身上包裹了一层(外部函数)的局部作用域. 这使得, 无论该函数对象在何处被调用, 都优先使用包裹在自己身上的这层作用域.

    # 常规函数
    import requests
    
    def get(url):
        response = requests.get(url)
        print(f'done:{url})
    
              
    # 如果后续要多次调用get函数爬取同一网站, 则每次都要输入一次网址          
    get('https://www.python.org')
    get('https://www.python.org')
    get('https://www.python.org')
              
    # 使用默认形参也只能解决一个网站
    get('https://www.cnblogs.com/bigb/')
    get('https://www.cnblogs.com/bigb/')
    get('https://www.cnblogs.com/bigb/')      
    

    我们可以用闭包函数解决上述问题

    # 闭包函数
    import requests
    
    # url是外部函数outer的形参, 可以把其看成函数outer局部作用域中的变量
    def outer(url): 
        def get():
            response = requests.get(url)
            print(f'done:{}')
         return get
    
    # 在外部函数空间作用域中存在 url = 'https://www.python.org'这个变量, 内部函数可以永久引用
    python = outer('https://www.python.org')
    
    python()  # get()
    python()
    python()
            
    

    装饰器

    什么是装饰器

    装饰器本质上就是一个闭包函数, 为被装饰对象添加额外功能

    装饰器的实现必须遵循两大原则:

    • 不修改被装饰对象源代码
    • 不修改被装饰对象的调用方式

    无参装饰器

    下面我们就用装饰器给既定函数f1增加计时功能

    import time
    
    def f1():
        '''被装饰函数'''
        print('this is f1')
        time.sleep(1)  # 程序休眠1秒
        
     # 定义time_count装饰器函数, func是形参名, 用来接收函数对象  
     def time_count(func):
    	'''装饰器函数'''
        
        # wrapper是辅助函数
        def wrapper():
    		start = time.time()
        	func()  # 使用函数对象调用函数
        	end = time.time()
        	print(f'程序耗费时长为: {end - start}')
            
         return wrapper
    
    
    f1 = time_count(f1)  # wrapper 
    f1()  # wrapper()
       
    '''
    this is f1
    程序耗费时长为: 1.0000574588775635
    ''' 
    

    如果f1是个有参函数我们该怎样通过装饰器传入参数呢?

    由上述例子我们知道, f1() = wrapper(), 因此我们给wrapper传参即可

    import time
    
    def f1(a):
        '''被装饰函数'''
        print('this is f1, 参数:', a)
        time.sleep(1)  # 程序休眠1秒
        
     # 定义time_count装饰器函数, func是形参名, 用来接收函数对象  
     def time_count(func):
        '''装饰器函数'''
        
        # wrapper是辅助函数
        def wrapper(*args,**kwargs):
    		start = time.time()
        	func(*args,**kwargs)  # 使用函数对象调用函数
        	end = time.time()
        	print(f'程序耗费时长为: {end - start}')
            
         return wrapper
    
    
    f1 = time_count(f1)  # wrapper 
    f1(1)  # wrapper()
    
    
    
    '''
    this is f1, 参数: 1
    程序耗费时长为: 1.0000572204589844
    '''
    
    

    如果函数f1有返回值我们如何通过装饰器实现呢?

    由于f1() = wrapper(), 因此f1 的返回值就是wrapper的返回值

    import time
    
    def f1(a):
        '''被装饰函数'''
        print('this is f1, 参数:', a)
        time.sleep(1)  # 程序休眠1秒
        return a
        
     # 定义time_count装饰器函数, func是形参名, 用来接收函数对象  
     def time_count(func):
        '''装饰器函数'''
        
        # wrapper是辅助函数
        def wrapper(*args,**kwargs):
    		start = time.time()
        	res = func(*args,**kwargs)  # 使用函数对象调用函数
        	end = time.time()
        	print(f'程序耗费时长为: {end - start}')
            return res
            
         return wrapper
    
    
    f1 = time_count(f1)  # wrapper 
    res = f1(1)
    print(res)
    
    
    '''
    this is f1, 参数: 1
    程序耗费时长为: 1.0000569820404053
    1
    '''
    
    

    还是不理解装饰器吗? 那就记住装饰器的模板吧!

    def deco(func):
        def wrapper(*args,**kwargs):
            # 添加功能
            res = func(*args, **kwargs)
            # 添加功能
            return res
        return wrapper
    

    装饰器语法糖:

    就是在被装饰函数上面单独写上@装饰器名 , 它实现的功能是f1 = time_count(f1)

    @time_count
    def f1(a):
        '''被装饰函数'''
        print('this is f1, 参数:', a)
        time.sleep(1)  # 程序休眠1秒
        return a
    
    
    res = f1(1)
    print(res)
    
    
    '''
    this is f1, 参数: 1
    程序耗费时长为: 1.0000569820404053
    1
    '''
    

    有参装饰器

    我们现在写一个登陆功能的装饰器

    # 登陆装饰器
    
    username_list = []
    
    def login(func):
        def wrapper(*args, **kwargs):
    
            if username_list:
                print('请勿重复登陆')
                res = func(*args, **kwargs)
                return res
    
            username_inp = input('请输入用户名: ')
            pwd_inp = input('请输入密码: ')
    
            # 从user_info读取用户信息
            with open('user_info', 'r', encoding='utf-8') as fr:
                for user_info in fr:
                    name, pwd = user_info.strip().split(':')
    
                    if name == username_inp and pwd == pwd_inp:
                        print('登录成功')
                        username_list.append(username_inp)
    
                        res = func(*args, **kwargs)  # 先调用 再返回
                        return res
                else:
                    print('用户名密码错误')
    
            res = func(*args, **kwargs)
    
            return res
    
        return wrapper
    

    上面我只实现了从user_info里面读取用户密码信息进行判断.

    现在我们想实现管理员登陆则从admin_info里面读取信息, 用户登陆则从user_info里面读取信息, 该怎么办呢?

    username_list = []
    
    def sanceng(role):
        
        def login(func):
            
            def wrapper(*args, **kwargs):
                
                if username_list:
                print('请勿重复登陆')
                res = func(*args, **kwargs)
                return res
    
            	username_inp = input('请输入用户名: ')
            	pwd_inp = input('请输入密码: ')
    
            	# 从{role}_info读取用户信息
            	with open(f'{role}_info', 'r', encoding='utf-8') as fr:
                	for user_info in fr:
                    	name, pwd = user_info.strip().split(':')
    
                    	if name == username_inp and pwd == pwd_inp:
                        	print('登录成功')
                        	username_list.append(username_inp)
    
                        	res = func(*args, **kwargs)  # 先调用 再返回
                        	return res
                		else:
                   			 print('用户名密码错误')
                       
    		return wrapper
        
        return login
    
    
    # 那我们在装饰 被装饰对象 时就要输入一个参数
    @sanceng(admin)
    def f1():
        pass
    
      
    
  • 相关阅读:
    php yield
    原来 php 中的 json_encode() 只支持utf-8.不支持gbk啊
    mongodb 二进制安装
    Centos 6.3 安装教程
    php 测试 程序执行时间,内存使用情况
    workerman vmstat服务器状态监控服务
    php大量数据 10M数据从查询到下载 【内存溢出,查询过慢】解决方案
    PHP_EOL DIRECTORY_SEPARATOR
    利用curl 模拟多线程
    Laravel 输出最后一条sql
  • 原文地址:https://www.cnblogs.com/bigb/p/11574779.html
Copyright © 2020-2023  润新知