python函数高级

函数是Python内建支持的一种封装,通过把大段代码拆成函数,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程程序设计的基本单元。

  • 变量可以指向函数,故可以将函数赋值给变量。
# 函数名赋值给变量
def func():
    print("hello world!")
    
new_func = func
new_func()

1. 高阶函数

一个函数接受另一个函数作为参数或者返回一个函数,即为高阶函数。

# 高阶函数
def test(func):
    x = 5
    print("hello world!")
    return func(x)

def num(x):
    return x ** 2

result = test(num)  # 接受一个函数作为参数
print(result)

2. 内置高阶函数

2.1 map函数
  • map(func, *iterables) --> map object
  • 接受一个函数和若干个可迭代对象作为参数,将函数依次作用于可迭代对象的每个元素,并将结果作为一个Iterator返回。
# map()h=函数
def square(num):
    return num ** 2

number = [1, 2, 3, 4]
result = map(square, number) 

print(type(result), result)
print(list(result))

# 执行结果
<class 'map'> <map object at 0x1053e5e48>
[1, 4, 9, 16]
2.2 reduce函数
  • python3中reduce函数已从全局名字空间中剔除。在functools模块中,from functools import reduce
  • reduce(function, sequence[, initial]) -> value
  • 接受一个函数和序列类型数据,该函数接受两个参数,该函数将序列的前两个元素作为函数参数执行,再将结果与后面元素依次做累积计算。
# reduce()函数
from functools import reduce

def multi(x, y ):
    return x * y

number = [1, 2, 3, 4, 5]
result = reduce(multi, number)
print(result)

# 执行结果
120
2.3 filter函数
  • filter函数用于过滤元素
  • filter(function or None, iterable) --> filter object
  • 接受一个函数和一个可迭代对象,将函数作用于每一个元素,根据结果为True或False决定是否保留元素,返回值为迭代器
# filter()函数:用于过滤元素

def odd(num):
    return num % 2

num = list(range(20))
result = filter(odd, num)
print(list(result))

# 执行结果
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
2.4 sorted函数
  • sorted函数用来对数据排序,也是一个高阶函数,不太明显。
  • sorted(iterable, key=None, reverse=False)
  • key可以接受一个函数作为排序依据,按函数执行结果排序后再返回原始元素排序。
# sorted()函数:排序
number = [-5, 9, 3, 27, -10]
m = sorted(number, key=abs)

print(m)

# 执行结果
[3, -5, 9, -10, 27]

3. 闭包

  • 一个函数返回一个内部函数,其内部函数引用了外部函数的相关参数和变量,则返回的内部函数及变量称为闭包。
  • 返回的函数并非立刻执行,当调用的时候才执行,延时执行
  • 特点是:引用外部参数和变量,即使外部函数结束(生成闭包的环境释放),该变量或参数仍然存在于闭包里面。
# 闭包
def make_func(name):
    
    def func():
        print("my name is %s." % name)
    
    return func

new_func = make_func("fengdi")
new_func()
  • 闭包无法修改外部函数的局部变量(若要修改,需使用nonlocal关键字声明)
  • 但可以修改外部函数中为可变类型的变量,比如列表
  • 尽量不要在闭包内引用循环变量或后续会发生变化的变量。若要使用循环变量,则要将函数参数绑定到循环变量的当前值。
# 闭包不要引用循环变量或后续会发生变化的变量
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())

def count():
    fs = []
    for i in range(1, 4):
        def f(i=i):
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())

# 执行结果 
9 
9 
9 
1 
4 
9

4. 装饰器

  • 装饰器:本质上是一个高阶函数,接受被装饰的函数为参数,返回一个包装后的函数,通过闭包实现。
  • 装饰器可在不改变原有函数的定义和调用形式来给原函数增加新的功能。

python实现装饰器有两种方式:① func = decorator(func)方式 ② @语法糖形式

# 装饰器:func = decorator(func)方式
def wrapper(func):
    def inner():
        print("------新功能添加------")
        func()
    
    return inner

def info():
    print("hello world!")
    
info = wrapper(info)   # 对Info函数进行装饰,添加功能,此时Info函数指向一个新的函数inner
info()

# 装饰器:@语法糖形式
def wrapper(func):
    def inner():
        print("------新功能添加------")
        func()
    
    return inner

@wrapper
def info():
    print("hello world!")
    
info()

# 执行结果
------新功能添加------
hello world!
------新功能添加------
hello world!
  • 程序从上往下执行过程中遇到装饰器就开始装饰,而不是调用函数时才开始装饰。
# 装饰器装饰时间
def wrapper(func):
    print("------装饰器开始装饰------")
    def inner():
        print("------新功能添加------")
        func()
    
    return inner

@wrapper
def info():
    print("hello world!")
    
# 执行结果
------装饰器开始装饰------
  • 当被装饰的函数有参数或者返回值时,返回的内部函数也拥有参数及返回值(return func())
# 装饰有返回值函数
def wrapper(func):
    def inner():
        print("------新功能添加------")
        return func()  # 被装饰函数具有返回值,则内部函数也应有返回值
    
    return inner

@wrapper
def info():
    return "hello world!!!"

result = info()
print(result)

# 执行结果 
------新功能添加------ 
hello world!!! 
# 装饰有参数函数
def wrapper(func):
    def inner(name):
        print("------新功能添加------")
        return func(name)  # 被装饰函数具有参数,内部函数也应有参数
    
    return inner

@wrapper
def info(name):
    return "my name is %s." % name

result = info("fengdi")
print(result)

# 执行结果 
------新功能添加------ 
my name is fengdi. 
  • 通用装饰器:不管被装饰的函数有无参数、有无返回值均适用
# 通用装饰器:有无参数,有无返回值,任意个参数均可
def wrapper(func):
    def inner(*args, **kwargs):
        print("------新功能添加------")
        return func(*args, **kwargs)  # 被装饰函数具有参数,内部函数也应有参数
    
    return inner
  • 装饰器可定义多个,装饰时离函数最近的装饰器先被调用进行装饰,函数执行时从上往下开始执行。
# 多个装饰器装饰一个函数
def wrapper1(func):
    print("------装饰器wrapper1开始装饰------")
    def inner():
        print("------新功能1添加------")
        return func()  # 被装饰函数具有参数,内部函数也应有参数
    
    return inner

def wrapper2(func):
    print("------装饰器wrapper2开始装饰------")
    def inner():
        print("------新功能2添加------")
        return func()  # 被装饰函数具有参数,内部函数也应有参数
    
    return inner

@wrapper1
@wrapper2
def info():
    print("hello world!")
    
print("-" * 40)
info()

# 执行结果
------装饰器wrapper2开始装饰------
------装饰器wrapper1开始装饰------
----------------------------------------
------新功能1添加------
------新功能2添加------
hello world!
  • 带参数的装饰器

    • 装饰器本身需要传入参数时,可在外部在嵌套一个函数接收参数,返回装饰器
    • 带参数一般是用来根据参数返回不同的装饰器
# 有参数的装饰器
def outer(num):
    def wrapper(func):
        def inner():
            print("---------权限验证%d---------" % num)
            func()
        return inner
    return wrapper

@outer(1)
def test1():
    print("--------test1---------")

@outer(2)
def test2():
    print("--------test2---------")
    
test1()
test2()

# 执行结果
---------权限验证1---------
--------test1---------
---------权限验证2---------
--------test2---------

5. 偏函数

  • 偏函数接受一个函数作为参数(将该函数的某些参数固定住),返回一个新的函数
  • 当函数参数太多,需要固定某些参数时,可使用partial创建一个新的函数,并将某些参数值固定
from functools import partial  

def multi(x, y): 
    return x * y  

double = partial(multi, y=2) 
print(double(2))