Python3快速入门—9.函数式编程

本文介绍了Python3的函数式编程,包括闭包、lambda表达式、高阶函数(map、reduce、filter)和装饰器的概念及应用。通过示例详细讲解了闭包的原理,如何使用lambda表达式和三元表达式简化代码,以及如何利用高阶函数对数据进行操作。最后,探讨了装饰器的使用方法,展示了如何在不修改原有函数的基础上增加功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

9.函数式编程

9.1闭包

9.1.1函数也是对象

在Python3中,没有函数重载。即当函数名相同,参数列表不同时,后面定义的函数会覆盖前面定义的函数。

#程序9-1

def add(x,y):

    return x+y

 

def add(x,y,z):

    return x+y+z

 

print(add(1,2))

print(add(1,2,3))

运行结果:

Traceback (most recent call last):

  File ".\run.py", line 10, in <module>

    print(add(1,2))

TypeError: add() missing 1 required positional argument: 'z'

在Python3中,一切皆对象。即函数、类都是对象。

#程序9-2

def add(x,y):

    return x+y

 

f = add

print(f(1,2))

 

class Student():

    def print_info(self):

        print('student')

 

Cls = Student

stu1 = Cls()

stu1.print_info()

运行结果:

3

student

9.1.2函数作为参数

在Python3中,函数也是对象,那么函数也可以作为其他函数的参数或返回值。

#程序9-3:函数作为参数

def square(x):

    return x*x

 

l = [1,2,3,4,5]

 

def fun(l,f):

    n = 0

    for m in l:

        l[n] = f(m)

        n += 1

 

fun(l,square)

print(l)

运行结果:

[1, 4, 9, 16, 25]

#程序9-4:函数作为返回值

def fun():

    def add(x,y):

        return x+y

    return add

 

f1 = fun()

print(f1)

print(f1(1,2))

f2 = fun()

print(f2)

print(f2(7,2))

运行结果:

<function fun.<locals>.add at 0x03490A08>

3

<function fun.<locals>.add at 0x035596A8>

9

函数fun称为封闭函数;函数add称为嵌套函数。当每执行一次封闭函数,都会创建一个嵌套函数的新实例。

9.1.3嵌套函数

嵌套函数的作用:函数封装;闭包。

#程序9-5:封装

def fun():

    def add(x,y):

        return x+y

    return add

 

def add(x,y,z):

    return x+y+z

 

f = fun()

print(f(1,2))

print(add(1,2,3))

运行结果:

3

6

由于嵌套函数被封闭函数保护起来,并不在全局作用域中,因此可以重新定义一个和嵌套函数同名的函数。

嵌套函数本质上属于封闭函数的局部对象,因此并不能在外部直接访问。

9.1.4闭包

在讲闭包之前,先看下面的代码。

#程序9-6

m = 1

def add(a):

    m = m + a

    return m

 

print(add(2))

print(m)

运行结果:

Traceback (most recent call last):

  File ".\run.py", line 21, in <module>

    print(add(2))

  File ".\run.py", line 18, in add

    m = m + a

UnboundLocalError: local variable 'm' referenced before assignment

m是全局变量,为什么在add函数中,m定义为局部变量?

当执行赋值运算符时,若左边的变量存在,则表示赋值操作;若左边的变量不存在,则表示创建新变量并赋值。在函数中,变量会优先检索局部变量,再去检索全局变量。

在add函数中,执行m + a操作时,会先检索局部变量m不存在,再去检索全局变量m,因此这里的m为全局变量。当执行m = 操作时,检索局部变量m不存在,会直接创建新的局部变量m,因此这里的m为局部变量。左边的m为局部变量,右边的m为全局变量,产生冲突运行失败。

#程序9-7:解决方法1

m = 1

 

def add(a):

    n = m + a

    return n

 

print(m)

print(add(2))

print(add(3))

运行结果:

1

3

4

#程序9-8:解决方法2

m = 1

 

def add(a):

    global m

    m = m + a

    return m

 

print('m = %d'%m)

print(add(2))

print('m = %d'%m)

print(add(3))

print('m = %d'%m)

运行结果:

m = 1

3

m = 3

6

m = 6

使用global关键字,在add函数内声明m为全局变量。由于使用了全局变量,因此每次运行的结果都会保存在全局变量m中。

问题:当一个函数每次运行都要保存执行结果,并用作下一次函数运行。该如何实现?

方法1:使用全局变量,函数内使用global关键字声明。函数每次运行都会修改全局变量,并且下一次函数运行时全局变量为修改后的数值。可参考程序9-8。

方法2:闭包

#程序9-9

m = 1

 

def fun(a):

    def add(b):

        nonlocal a

        a = a + b

        return a

    return add

 

f = fun(m)

print(f(2))

print(f(3))

print('m = %d'%m)

运行结果:

3

6

m = 1

闭包:1.必须包含一个嵌套函数;2.嵌套函数必须引用封闭函数中传入参数或定义变量;3.封闭函数必须返回嵌套函数。

在封闭函数中传入的参数或定义的变量,我们称为环境变量(或自由变量)。在嵌套函数中使用环境变量需要使用关键字nonlocal声明。

环境变量的生命周期和封闭函数相同,将封闭函数赋值给变量后,此封闭函数中的环境变量就已经定义在内存中;嵌套函数可以直接调用环境变量。

#程序9-10:环境变量

m = 3

 

def fun(a):

    def add(b):

        nonlocal a

        a = a + b

        return a

    return add

 

f = fun(m)

print(f(2))

print(f(3))

print('m = %d'%m)

f1 = fun(m)

print(f1(4))

print(f1(5))

print('m = %d'%m)

运行结果:

5

8

m = 3

7

12

m = 3

总结:

1.在封闭函数中传入参数为全局变量,则封闭函数会定义一个环境变量来保存全局变量的数值。因此在嵌套函数中修改其变量的数值,实际上修改的是在封闭函数中定义的环境变量,而不是全局变量。这也是在函数运行后,全局变量m依旧是3的原因。

2.在程序9-10中,执行f = fun(m)和f1 = fun(m),表示将闭包的函数分别赋值给f和f1,f和f1的地址不同,因此f和f1中的环境变量也是不同的。

3.方法1虽然使用全局变量也可以实现,但是在代码尽量不要过多的使用全局变量,以防名称覆盖以及参数调用错误。

4.环境变量本质上属于局部变量,由于将闭包的函数赋值给变量,导致封闭函数的生命周期和变量一致,也因此环境变量的生命周期和赋值的变量一致。

9.1.5使用闭包解决实际问题

在地图上,一位路人的坐标为(3,5),其每次移动的相对坐标为(x,y),求路人的绝对坐标。

#程序9-11

m = [3,5]

 

def fun(a):

    def add(b):

        nonlocal a

        c = 0

        while c < len(b):

            a[c] = a[c] + b[c]

            c += 1

        return a

    return add

 

f = fun(m)

print(f([2,4]))

print(f([6,9]))

运行结果:

[5, 9]

[11, 18]

9.2 lambda表达式和三元表达式

9.2.1 lambda表达式

lambda表达式又称为匿名函数,其语法格式:lambda parameter_list: expression。

其中,lambda表示关键字;parameter_list为参数列表,参数之间用逗号隔开;expression为返回的表达式,且表达式只能有一个(注:只能是表达式,不能是语句;即不能包含赋值运算符)。

#程序9-12

add = lambda x,y:x+y

print(add(1,2))

运行结果:

3

lambda表达式一般和高阶函数一起使用。

9.2.2三元表达式

三元表达式的语法格式:expression_T if expression else expression_F。

若表达式expression为真,则执行expression_T;若未假,则执行expression_F。

#程序9-13

a = 1

b = 3

 

ret = b-a if a < b else a-b

 

print(ret)

运行结果:

2

9.3高阶函数

9.3.1 map函数

map函数又被称为映射,其语法格式:map(func, *iterables) --> map object。

其中,func参数表示函数,其必须有返回值(若无返回值,则map返回序列中元素全是None);*iterables是可变参数,用来表示多个序列、集合、字典;map object表示返回值是map对象。

函数作用:对*iterables中的每一个元素,都执行一次func函数。

#程序9-14

list1 = [1,2,3,4,5,6]

list2 = [8,7,6,5,4,3,2,1]

 

def square(x):

    return x*x

 

def add(x,y):

    return x+y

 

ret1 = map(square,list1)

print(ret1)

print(list(ret1))

 

ret2 = map(add,list1,list2)

print(ret2)

print(list(ret2))

运行结果:

<map object at 0x008E08B0>

[1, 4, 9, 16, 25, 36]

<map object at 0x008E09B0>

[9, 9, 9, 9, 9, 9]

当map函数中有多个序列时,选择元素最少的序列如list1,其长度作为map函数返回序列的长度。

为了简化代码,map中的func可以使用lambda表达式。

#程序9-15

list1 = [1,2,3,4,5,6]

list2 = [8,7,6,5,4,3,2,1]

 

ret1 = map(lambda x:x*x,list1)

print(ret1)

print(list(ret1))

 

ret2 = map(lambda x,y:x+y,list1,list2)

print(ret2)

print(list(ret2))

运行结果:

<map object at 0x00730890>

[1, 4, 9, 16, 25, 36]

<map object at 0x00730990>

[9, 9, 9, 9, 9, 9]

map函数的返回值也可以是其他数据类型,如列表、元组、集合。

#程序9-16

old_list = [1,2,3,4,5,6]

 

ret = map(lambda x:x*x,old_list)

print(ret)

# print(list(ret))

# print(tuple(ret))

print(set(ret))

运行结果:

<map object at 0x00FBF610>

{1, 4, 36, 9, 16, 25}

9.3.2 reduce函数

reduce函数又被称为归约,其语法格式:def reduce(function, sequence, initial)。

其中,参数function表示为函数(参数必须为2个);参数sequence表示序列;initial表示初始值。注:使用reduce函数需要模块functools。

#程序9-17

from functools import reduce

 

old_list = [1,2,3,4,5,6,7,8,9]

 

ret1 = reduce(lambda x,y:x+y,old_list)

print(ret1)

 

ret2 = reduce(lambda x,y:x+y,old_list,5)

print(ret2)

运行结果:
45

50

reduce函数将序列sequence中的元素传递给函数function,每次传递2个。若无initial,则默认initial为0;若有initial,则在第一次传递参数时,作为第一个参数传递给函数function。当每次function执行结束后,其返回值作为下一次function运行的第一个参数。因此reduce函数的作用是累积序列。

9.3.3 filter函数

filter函数语法格式:filter(function or None, iterable) --> filter object。参数function表示函数,参数iterable表示序列。序列中的每一个元素作为参数传递给函数进行判断,然后返回True或False,将返回True的元素存放到新列表中。

filter函数作用是过滤序列。

#程序9-18

old_list = [1,'a',2,'b',3,'c',4,'d',5,'e']

 

ret = filter(lambda x:True if isinstance(x,str) else False,old_list)

print(list(ret))

运行结果:

['a', 'b', 'c', 'd', 'e']

9.4装饰器

在前面学习了闭包,若封闭函数中传入参数是一个函数,该怎么办?

#程序9-19

def decorator(func):

    def wrapper():

        print('Start: '+func.__name__)

        func()

        print('End: '+func.__name__)

    return wrapper

 

def function_one():

    print('this is function_one')

 

f1 = decorator(function_one)

f1()

运行结果:

Start: function_one

this is function_one

End: function_one

在不修改函数function_one的前提下,增加了function_one的功能,即在function_one执行前和执行结束分别打印函数名称(可用于调试)。函数decorator就可以称为一个装饰器。

由于使用f1 = decorator(function_one)和f1()来调用function_one比较麻烦,可以使用关键字@来实现装饰效果。

#程序9-20

def decorator(func):

    def wrapper():

        print('Start: '+func.__name__)

        func()

        print('End: '+func.__name__)

    return wrapper

 

@decorator

def function_one():

    print('this is function_one')

 

function_one()

运行结果:

Start: function_one

this is function_one

End: function_one

装饰器基本知识1:一个函数用户可以有多个装饰器,装饰器的执行顺序从上到下。

#程序9-21

import time

def dec_time(func):

    def wrapper():

        print('time start')

        strat_time = time.time()

        func()

        end_time = time.time()

        print('Function runtime is %f'%(end_time-strat_time))

    return wrapper

 

 

def decorator(func):

    def wrapper():

        print('Start: '+func.__name__)

        func()

        print('End: '+func.__name__)

    return wrapper

 

@decorator

@dec_time

def function_one():

    print('this is function_one')

 

function_one()

运行结果:

Start: wrapper

time start

this is function_one

Function runtime is 0.000997

End: wrapper

装饰器基本知识2:装饰器也可以传入参数,但装饰器的具体实现需要修改。

#程序9-22

parm = 1.234

def decorator_parameter(parm):

    def decorator(func):

        def wrapper():

            print('Start: '+func.__name__)

            print('parm = %f'%parm)

            func()

            print('End: '+func.__name__)

        return wrapper

    return decorator

 

@decorator_parameter(parm)

def function_one():

    print('this is function_one')

 

function_one()

运行结果:

Start: function_one

parm = 1.234000

this is function_one

End: function_one

对于3重封装的装饰器很难理解,实际上decorator_parameter(parm)函数执行后返回decorator,因此@decorator_parameter(parm) = @decorator。

装饰器基本知识3:被装饰的函数(function_one)也可以传入参数,为了表示参数的一般性,将wrapper参数设置为*args和**kwargs。其中,*args表示可变参数,**kwargs表示关键字可变参数。

#程序9-23

def decorator(func):

    def wrapper(*args,**kwargs):

        print('Start: '+func.__name__)

        func(*args,**kwargs)

        print('End: '+func.__name__)

    return wrapper

 

@decorator

def function_one():

    print('this is function_one')

 

@decorator

def function_two(name):

    print('this is function_two, name is '+str(name))

 

@decorator

def function_three(*args,**kwargs):

    print('this is function_three',end = ', ')

    print(args,end = ', ')

    print(kwargs)

 

function_one()

function_two('zhangsan')

function_three('lisi','China',age = 18, profession = 'student')

运行结果:

Start: function_one

this is function_one

End: function_one

Start: function_two

this is function_two, name is zhangsan

End: function_two

Start: function_three

this is function_three, ('lisi', 'China'), {'age': 18, 'profession': 'student'}

End: function_three

装饰器的封闭函数中传入被装饰函数的函数名,嵌套函数中传入被装饰函数的参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值