• 一文搞懂Python函数(匿名函数、嵌套函数、闭包、装饰器)!


    Python函数定义、匿名函数、嵌套函数、闭包、装饰器

    函数核心理解

    • 函数也是对象,可以把函数赋予变量
    • 可以把函数当作参数,传入另一个函数中
    • 可以在函数里定义函数,函数嵌套
    • 函数的返回值也可以是函数对象,闭包

    1. 函数定义

    def name(param1, param2, ..., paramN):
        statements
        return/yield value # optional
    
    • def是可执行语句,函数直到被调用前,都是不存在的,当程序调用函数时,def语句才会创建一个新的函数对象,并赋予其名字

    • 主程序调用函数时,必须保证这个函数此前已经定义过,不然会报错

    • 在函数内部调用其他函数时,函数间哪个申明在前、哪个在后无所谓,只要保证调用时,所需的函数都已经声明定义

    • python不用考虑输入的数据类型,而是将其交给具体的代码去判断执行,这种行为称为多态。

    • python函数的参数可以设定默认值,可以指定数据类型

      def name(param1 = 0, param2: int, ..., paramN):
      

    函数作用

    • 减少代码的重复性
    • 模块化代码

    2. 嵌套函数

    2.1 作用
    • 能够保证内部函数的隐私,内部的函数只能被外部函数所调用和访问,不会暴露在全局作用域
    • 合理使用,可以提高程序的运行效率
    2.2 函数变量作用域
    • 局部变量:函数内部定义的,只在函数内部有效,一旦执行完毕,局部变量就会被回收,无法访问
    • 全局变量定义在整个层次上的,不能在函数内部随意修改全局变量的值,如要修改,加global关键字
    • 函数内部,局部变量和全局变量同名,局部变量会覆盖全局变量
    • 嵌套函数,内部函数可以访问外部函数定义的变量,但无法修改,如要修改,加nonlocal关键字
    • 内部函数的变量和外部函数变量同名,覆盖
    MIN = 1 # 全局变量
    MAX = 8
    print(f"MIN={MIN},MAX={MAX}")
    def f1():
        global MIN # 使用global关键字 修改全局变量
        MIN += 1
        a = 5  # 局部变量
        b = 1
        print(f"MIN={MIN},a={a},b={b}")
        def f2():
            MAX = 9 # 局部变量与全局变量同名,局部变量会覆盖全局变量
            nonlocal a # 使用nonlocal关键字 修改外部函数的变量
            a += 1
            b = 2 # 内部函数变量与外部函数变量同名,覆盖
            print(f"MIN={MIN},MAX={MAX},a={a},b={b}")
        f2()  # 内部函数被外部函数调用
    
    f1()
    print(f"MIN={MIN},MAX={MAX}")
    
    MIN=1,MAX=8
    MIN=2,a=5,b=1
    MIN=2,MAX=9,a=6,b=2
    MIN=2,MAX=8
    

    3. 闭包

    3.1 特点
    • 和嵌套函数类似,只是,外部函数返回的是一个函数,而不是一个具体的值
    • 返回的函数通常赋予一个变量,这个变量可以在后面被继续执行调用
    • 可以简化程序的复杂度,提高可读性
    3.2 实例
    # 计算一个数的n次幂
    def nth_power(exponent):
        def exponent_of(base):
            return base **exponent
        return exponent_of # 返回一个函数
    
    # 调用函数
    square = nth_power(2)
    print(square)
    print(square(3))
    
    <function nth_power.<locals>.exponent_of at 0x7f3120911b90>
    9
    

    4. 装饰器

    4.1 形式和作用
    • @装饰器函数,等价于,原函数名=装饰器函数(原函数名)
    • 装饰器就是通过装饰器函数,来修改原函数的一些功能,使得原函数不需要修改,也就是扩展了原函数的功能
    4.2 装饰器函数写法
    # 简单装饰器
    def my_decorator(func):
        def wrapper():
            print('wrapper of decorator')
            func()
        return wrapper
    # 带参数的装饰器
    def my_decorator(func):
        def wrapper(message):
            print('wrapper of decorator')
            func(message)
        return wrapper
    # 通用的带参数的装饰器
    def my_decorator(func):
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper
    # 保留原函数的元信息,将原函数的元信息,拷贝到对应的装饰器函数里
    import functools
    def my_decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('wrapper of decorator')
            func(*args, **kwargs)
        return wrapper
    
    @my_decorator
    def greet(message):
        print(message)
        
    greet('hello world')
    
    # 输出
    wrapper of decorator
    hello world
    
    # 类装饰器,依赖函数__call__()
    class Count:
        def __init__(self, func):
            self.func = func
            self.num_calls = 0
    
        def __call__(self, *args, **kwargs):
            self.num_calls += 1
            print('num of calls is: {}'.format(self.num_calls))
            return self.func(*args, **kwargs)
    
    @Count
    def example():
        print("hello world")
    
    example()
    
    # 输出
    num of calls is: 1
    hello world
    
    4.3 装饰器用法实例
    • 身份认证、日志记录
    • 测试某些函数的执行时间
    import time
    import functools
    
    def log_execution_time(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start = time.perf_counter()
            res = func(*args, **kwargs)
            end = time.perf_counter()
            print(f"{func.__name__} took {(end - start) * 1000)} ms")
            return res
        return wrapper
        
    @log_execution_time
    def calculate_similarity(items):
        ...
    
    • 缓存

      python中内置的LRU cache,@lru_cache,会缓存进程中的函数参数和结果,缓存满了之后,会删除访问时间最早的数据

    • 工作中,二次开发,在原来的需求基础上做优化,原逻辑不需要修改的化,只需增加新的业务场景的时候

    5. 匿名函数

    5.1 格式
    lambda argument1, argument2,... argumentN : expression
    
    • 此表达式返回的是一个函数对象,用法举例
     # 计算一个数的平方
    square = lambda x: x**2 # 返回一个函数对象
    a = square(3) # 调用函数
    print(a)
    # 9
    
    5.2 使用原则
    • lambda是一个表达式,不是一个语句,只能写成一行
    • 程序中需要使用一个函数完成一个简单的共嗯那个,并且该函数只调用一次
    5.3 使用方式
    • 1.用在列表内部
    # 计算列表0-9的数的平方
    li = [(lambda x: x*x)(x) for x in range(10)]
    print(li)
    
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    • 2.用作某些函数的参数
    # 按列表中元组的第1个元素排序
    lis = [(1, 20), (3, 0), (9, 10), (2, -1)]
    lis.sort(key=lambda x: x[0]) 
    print(lis)
    
    [(1, 20), (2, -1), (3, 0), (9, 10)]
    
    # 对一个字典,根据值进行由高到低的排序
    d = {"mike": 10, "luck": 2, "ben": 30}
    new_li = sorted(d.items(), key=lambda x: x[1], reverse=True) # 返回的是列表嵌套元组类型
    new_d = dict(new_li)
    print(d,'
    ', new_li, '
    ', new_d, sep='')
    
    {'mike': 10, 'luck': 2, 'ben': 30}
    [('ben', 30), ('mike', 10), ('luck', 2)]
    {'ben': 30, 'mike': 10, 'luck': 2}
    
    • 3.数据清洗中,常用lambda函数

    6. python函数式编程

    6.1 概念
    • 指代码中每一块都是不可变的,都由纯函数的形式组成
    • 纯函数,是指函数本身相互独立、互不影响,对于相同的输入,总会有相同的输出
    6.2函数式编程的优缺点
    • 优点主要在于其纯函数和不可变的特性使程序更加健壮,易于调试和测试
    • 缺点主要在于限制多,难写
    6.3 map()、filter() 和 reduce()函数
    • map(function, iterable),对序列中的每个元素都运用function这个函数,返回一个迭代器
    # 对列表中的每个元素乘以2
    li = [1, 2, 3, 4, 5]
    new_list_1 = map(lambda x: x*2, li)
    print(list(new_list_1)) # 将迭代器转换为列表
    
    [2, 4, 6, 8, 10]
    
    • filter(function, iterable),对序列中的每个元素,都使用function判断,并返回True或者False,最后将返回True的元素组成一个新的可遍历的集合,返回迭代器类型
    # 返回列表中能够整除2的元素
    li = [1, 2, 3, 4, 5]
    new_list_2 = filter(lambda x: x % 2 == 0, li)
    print(list(new_list_2))
    
    [2, 4]
    
    • reduce(function, iterable),规定有两个参数,表示对序列中的每个元素以及上一次调用后的结果,运用function进行计算,最后返回的是一个单独的数值
    # 计算列表元素的乘积
    from functools import reduce
    li = [1, 2, 3, 4, 5]
    product = reduce(lambda x, y: x * y, li)
    print(product)
    
    120
    
  • 相关阅读:
    幸福之路
    mysql8.0.25安装配置教程(windows 64位)
    解决git@gitee.com: Permission denied (publickey).
    python路径拼接os.path.join()函数的用法
    如何正确的看待Python里的GIL锁
    安装激活Golang
    Django的Orm操作数据库
    爬虫技术栈点
    Django
    Python/数据库/Django笔记
  • 原文地址:https://www.cnblogs.com/donghe123/p/13279730.html
Copyright © 2020-2023  润新知