首页 > 技术文章 > python 高级函数

zhijiyiyu 2022-01-21 11:29 原文

python高级函数

一:闭包

1.1 什么是闭包

python 函数是支持嵌套的。如果在一个内部函数中对外函数作用域(非全局作用域)的变量进行引用,那么内部函数就会被称为闭包.

闭包需要满足 3 个条件

  1. 存在与两个嵌套关系的函数中,并且闭包是内部函数
  2. 内部函数引用了外部函数的变量
  3. 外部函数会返回内部函数的函数名

1.2 python函数带小括号和不带小括号的区别

1、不带括号时,调用的是这个函数本身 ,是整个函数体,是一个函数对象,不需等该函数执行完成

2、带括号(此时必须传入需要的参数),调用的是函数的return结果,需要等待函数执行完成的结果

如果函数本身带有参数的时候,带括号就就必须带参数,同理函数本身不带参数,带括号就不能带参数


1.3 演示内置函数

# 演示内置函数.内置函数是闭包的基础

def a(): #第一步,定义外部函数
    b = 1  # 3,执行外部函数代码

    def c():  # 4 定义内部函数
        print(b)  #执行内部函数代码

    c()  # 5 调用内部函数

a()  # 2 调用外部函数

# 输出结果:
1

1.4 演示外部函数以接收返回值方式访问内部函数

# 演示把内部函数返回(闭包的必要条件),使得外部可以用接收返回值的方式,来访问内部函数
def a():
    def b():
        return 1  # 定义了内部函数的返回值为1

    # 不带括号时,调用的是这个函数本身 ,是整个函数体,是一个函数对象,不需等该函数执行完成
    return b  # 直接返回函数名,

# 使用变量rst 接收了外部函数的返回值.rst就相当于b
rst = a()

print(rst)  #rst就是内部函数b, 可以理解为print(b)(但是不能使用该语句)
print(rst()) #  rst() 是调用内部函数,可以理解为print(b())(但是不能使用该语句)
print(a()())  # a()() 和rst()相同

# 输出:
<function a.<locals>.b at 0x000001F3B6C83160>  #返回的是a.b
1
1

1.5演示一个函数作为另一个函数的参数

# 使用一个函数作为另一个函数参数的情况

# func_a ,接收到外部传入的参数,参数是函数名,表示是该函数本身而不是该函数执行结果
def a(func_a):  # 可以传递任意函数
    print("您好,我是a")

    # 将传入的值,加上(),表示调用该函数体的执行结果.
    func_a()  # 可以对已定义的函数做额外的操作,而不需要修改原来的函数
    print("goodby")


def b():
    print("您好,我是b")


def c():
    print("您好,我是c")


def d():
    print("您好,我是d")


# 将函数体作为参数传递给 a 函数
a(b)
a(c)
a(d)

# 输出结果:
"""
您好,我是a
您好,我是b
goodby
您好,我是a
您好,我是c
goodby
您好,我是a
您好,我是d
goodby
"""

1.6演示闭包函数

# 演示闭包函数
def outer(start=0): # 1,定义外部函数.默认参数start=0
    count = [start] # 3 执行外部函数代码.count = [5]

    def inner():   # 4 定义内部函数
        count[0] += 1  # 8 执行内部函数代码,count值==>6
        return count[0]  #9 返回值为count[0],即6

    # 返回值为内部函数名,相当于返回该函数体.
    return inner # 5 返回值


#2, 调用外部参数,传入值为5
out = outer(5)  # 6, out 变量接收外部函数返回值.该返回值为内部函数体.

print(out())   # 7,  此时out(),相当于inner(),调用内部函数,获取返回值
               # 10, print 打印内部函数的返回值,即print(6)
  
  
# 输出结果:
6

1.7 使用闭包实现案例

# 有银行卡才能执行汇款操作
# 外部函数为创建银行卡
# 内部函数为汇款的操作

def bank(is_vip, action):
    if is_vip:
        print("尊敬的客户您好,欢迎光临!")
    else:
        print("您好,给您新办了一张卡")

    if action == "hui":
        def remit():
            print("进行汇款操作")
        return remit

    if action == "cun":
        def cunkuan():
            print("进行存款操作")
        return cunkuan


card = bank(False,"cun")
card()

card = bank(True,"hui")
card()

# 输出结果:
您好,给您新办了一张卡
进行存款操作
尊敬的客户您好,欢迎光临!
进行汇款操作

二: 装饰器

2.1 什么是装饰器

假设我们已经定义了一个函数,后续可能会增加临时的需求,例如插入日志,我们可以增加一个包裹函数,由它来负责这些额外的需求,这个包括函数就是装饰器

装饰器主要用于以下场景:

  • 引入日志
  • 函数执行时间统计
  • 执行函数前预备处理
  • 执行函数后清理功能
  • 权限校验
  • 缓存

2.2 演示装饰器

装饰器是一个函数,它需要接收一个参数,该参数表示被修饰的函数.

# 演示装饰器
def a(fun_a):  # 1,定义外部函数(装饰器)
    print("装饰器开始工作!")  # 4, 外部函数(装饰器)代码执行

    def b():   # 5, 定义内部函数(闭包)
        print("闭包开始工作")  # 10, 执行内部函数的代码
        fun_a()  # 11,这是外部函数的参数,由于传递进入的是一个被装饰函数的函数名.加上小括号后,相当于调用该函数,获取该函数的执行结果decorator()
                 # 13 获取装饰函数的执行结果

    print("装饰器工作结束")  # 6, 外部函数代码执行
    return b  # 7 返回值. 返回值为内部函数名.表示是该函数体


def decorator_a():  # 2, 定义装饰函数
    print("这是被装饰函数")  # 12执行装饰函数内部代码


rst = a(decorator_a)  # 3, 调用外部函数(装饰器)a,传入参数为函数名,使用变量rst 接收函数 a 的返回值
                      # 8, rst 接收a的返回值.由于返回值是内部函数b的函数体,此时,rst 就相当于内部函数b

rst()  # 9, 执行rst(),就相当于b(),调用内部函数b(),获取该函数执行结果
       # 14, 获取内部函数的执行结果

# 输出结果:
"""
装饰器开始工作!
装饰器工作结束
闭包开始工作
这是被装饰函数
"""

2.3 演示装饰器(2)

通过在函数定义的前面添加@符号和装饰器名,实现装饰器对函数的包装

from functools import wraps

def a(func_a):
    print("装饰器开始工作")
    @wraps(func_a)  #可以防止注释使得函数名错乱

    def b():
        print("闭包开始工作")
        func_a()

    print("装饰器工作结束")
    return b


@a # 等效于abc = a(abc)
def abc():
    print("想要被装饰")

abc()
print("函数名是",abc.__name__)


# 输出结果:
"""
装饰器开始工作
装饰器工作结束
闭包开始工作
想要被装饰
函数名是 abc
"""

注意: 如果多个装饰器应用在一个函数上,调用顺序是从下至上

如:

@warp_one
@warp_two
def test():
  print("---test---")
  
  
# 执行顺序:
先执行@warp_two
后执行@warp_one

2.4 演示装饰有参数的函数

def warp(func):
    def inner(a, b):
        print("开始验证权限")
        func(a, b)

    return inner


# @warp
def test(a, b):
    print("a=%d, b=%d" % (a, b))


test = warp(test)   
test(1, 2)

# 输出结果:
开始验证权限
a=1, b=2

2.5 带有返回值的装饰器

# 演示带有返回值的装饰器
def func(function_name):
    def func_in():
        return function_name()

    return func_in


@func  #等效于 test=func(test)
def test():
    return "hello world"


print(test())

# 输出结果:
hello world

2.6 带有参数的装饰器

如果给装饰器添加参数,需要增加一层包装,先传递参数,然后再传递函数名.

def outer(args):
    def func(a):
        print("这是一个有返回值的闭包")

        def func_in():
            print(args)
            return a()

        return func_in

    return func


func = outer("hello")

@func  # 等效于test=func(test)
def test():
    return "hello world"

print(test())

# 输出结果:
"""
这是一个有返回值的闭包
hello
hello world
"""

三:闭包,装饰器总结

一:闭包:

  1. 一个函数包含另一个函数

  2. 外部函数return了内部函数名

  3. 内部函数调用了外部函数的变量

----- 这个内部函数叫做闭包

特点:闭包不能直接别调用,而是需要调用外部函数获得返回值;

使用该返回值(),来调用内部函数


二:装饰器:

  1. 在外部函数的参数部分接收函数名

  2. 在内部函数的函数体中调用参数对应的函数

  3. 外部函数返回了内部函数名

  4. 调用外部函数传入函数名获取返回值(闭包)

  5. 通过闭包调用,实现对参数对应的函数调用

  6. 可以通过@装饰器名,来替代闭包传参的过程

特点:装饰器的调用相对安全可靠,并且不会改变原函数的逻辑


四: 常见的python内置函数

4.1 map函数

map 函数会根据提供的函数对指定的序列做映射

map 函数的定义如下:

  • map(function,iterable...
  • 参数function 表示函数的名称
  • 参数iterable 可以是序列,支持迭代的容器或者迭代器

map 函数的作用就是以 iterable 中每个元组调用function函数,把每次调用后返回的结果保存为迭代器对象

# 演示map 函数
func = lambda x: x + 2
rst = map(func, (1, 2, 3, 4, 5))

print(list(rst))
# 输出结果
[3, 4, 5, 6, 7]

func = lambda x,y:  x + y
rst = map(func, (1, 2, 3, 4, 5), [0, 7, 4, 6, 8])

print(list(rst))

# 输出结果:
[1, 9, 7, 10, 13]

map 函数的执行过程

image-20220121112017652


4.2 filter 函数

filter 函数会对指定序列执行过滤操作

filter 函数定义如下:

  • filter(function, iterable)
  • function 参数可以是函数名成,或者None
  • iterable参数可以是序列,支持迭代器的容器,或者迭代器

# 演示filter函数

func = lambda x: x % 2

# 注意,0代表False , 1 代表True.
rst = filter(func, [1, 2, 3, 4, 5, 6, 7, 8])
print(list(rst))

func = lambda x: x > 5
rst = filter(func, [1, 2, 3, 4, 5, 6, 7, 8])
print(list(rst))

# 输出结果:
[1, 3, 5, 7]
[6, 7, 8]

filter 函数的执行过程

image-20220121112349422


4.3 reduce 函数

reduce 函数会对参数序列中的元素进行累积
.再python3,中,需要先 fucntools模块引入

reduce函数的定义如下:

  • reduce(function,iterable[,initializer])
  • function 是一个带有两个参数的函数.function 参数不能为None
  • iterable 是一个迭代器对象
  • initializer 表示固定的初始值

# 演示reduce 函数
from functools import reduce

func = lambda x,y: x + y
rst = reduce(func,[1,2,3,4,5,6,7,8,9,10])
print(rst)

# 输出结果:
55

推荐阅读