【python学习笔记】task06 函数与Lambda表达式

本文深入探讨Python中的函数定义、调用、参数、返回值、作用域等核心概念,详解闭包、递归的使用技巧,同时介绍Lambda表达式在函数式编程中的应用。

函数

1.函数的定义

基本格式

def functionname( parameters ):
           "函数_文档字符串"
           function_suite
           return [expression]

(1)函数以def关键词开头,后接函数名圆括号()
(2)任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
(3)函数执行的代码以冒号起始,并且缩进。
(4)return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None
 

2.调用函数

如需调用函数,使用函数名称后跟括号
【例子】定义加法函数,并调用

def add(a, b):
    print(a + b)


add(1, 2)  # 3
add([1, 2, 3], [4, 5, 6]) # [1, 2, 3, 4, 5, 6]

 

3.函数文档

即函数定义中"函数_文档字符串"这一部分
(1)作用:方便函数功能、参数以及返回值的含义能够被调用者知悉.,能够在调用时快捷查看函数相关信息
(2)与注释的区别:需要查看函数定义时才能看到
(3)查看方法:函数名.__doc__或者help(函数名)
【例子】定义并查看函数文档

def MyFirstFunction(name):
    "函数定义过程中name是形参"
    # 因为Ta只是一个形式,表示占据一个参数位置
    print('传递进来的{0}叫做实参,因为Ta是具体的参数值!'.format(name))


MyFirstFunction('老马的程序人生')  
# 传递进来的老马的程序人生叫做实参,因为Ta是具体的参数值!

print(MyFirstFunction.__doc__)  
# 函数定义过程中name是形参

help(MyFirstFunction)
# Help on function MyFirstFunction in module __main__:
# MyFirstFunction(name)
#    函数定义过程中name是形参

 

4.函数参数

参数类型格式作用
位置参数arg1def functionname(arg1)在调用函数时位置固定的参数
默认参数arg2=vdef functionname(arg1, arg2=v)调用函数时,默认参数的值如果没有传入,则被认为是默认值,默认参数必须放在位置参数的后面
可变参数*argsdef functionname(arg1, arg2=v, *args)传入的参数个数是可变的,可以是 0, 1, 2 到任意个,是不定长的参数
关键字参数**kwdef functionname(arg1, arg2=v, *args, **kw)可以是从零个到任意个,自动组装成字典,使用 key = value 语法发送参数
命名关键字参数*, nkwdef functionname(arg1, arg2=v, *args, *, nkw, **kw)如果要限制关键字参数的名字,就可以用「命名关键字参数」,使用命名关键字参数时,要特别注意不能缺少参数名

【例子】命名关键字参数的使用时候,如果没有写命名关键字参数,会误将该位置的参数当成「位置参数」,致使程序会报错

def printinfo(arg1, *, nkw, **kwargs):
    print(arg1)
    print(nkw)
    print(kwargs)


printinfo(70, nkw=10, a=1, b=2)
# 70
# 10
# {'a': 1, 'b': 2}

printinfo(70, 10, a=1, b=2)
# TypeError: printinfo() takes 1 positional argument but 2 were give

注意:
(1)Python 允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
【例子】本例子中在调用函数时候参数的顺序和函数定义的不一致,但是Python能够识别

def printinfo(name, age):
    print('Name:{0},Age:{1}'.format(name, age))


printinfo(age=8, name='小马')  # Name:小马,Age:8

(2)可变参数与关键字参数的区别在于:

  • 可变参数允许传入零个到任意个参数,它们在函数调用时自动组装为一个元组 (tuple)。
  • 关键字参数允许传入零个到任意个参数,它们在函数内部自动组装为一个字典 (dict)。
    【例子】比较可变参数与关键字参数
def printinfo(arg1,*args,**kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    
#只传入了位置参数和可变参数
printinfo(70,60,50)
# 70
# (60, 50)
# {}

#传入位置参数、河边参数和关键字参数
printinfo(70,60,50,a=1,b=2)
# 70
# (60, 50)
# {'a': 1, 'b': 2}

(3)在 Python 中定义函数,可以用位置参数、默认参数、可变参数、命名关键字参数和关键字参数,这 5 种参数中的 4 个都可以一起使用,但是注意,参数定义的顺序必须是:

  • 位置参数、默认参数、可变参数和关键字参数。
  • 位置参数、默认参数、命名关键字参数和关键字参数。
     

5.函数的返回值

通过return语句实现
【例子】对于无参数的函数实现返回值

def back():
    return 1, '小马的程序人生', 3.14


print(back())  # (1, '小马的程序人生', 3.14)

 

6.变量作用域

(1)局部变量:定义在函数内部的变量拥有局部作用域,称为局部变量,局部变量只能在其被声明的函数内部访问,当内部作用域想修改外部作用域的变量时,需要用到globalnonlocal关键字了

num = 1


def fun1():
    global num  # 需要使用 global 关键字声明
    print(num)  # 1
    num = 123
    print(num)  # 123


fun1()
print(num)  # 123

(2)全局变量:定义在函数外部的变量拥有全局作用域,称为全局变量,全局变量可以在整个程序范围内访问
 

7.内嵌函数

在函数中又定义了函数,如下面的例子,调用上层函数时候,下层函数也被执行了

def outer():
    print('outer函数在这被调用')

    def inner():
        print('inner函数在这被调用')

    inner()  # 该函数只能在outer函数内部被调用


outer()
# outer函数在这被调用
# inner函数在这被调用

 

8.闭包

(1)闭包是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数
(2)如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包。
(3)通过闭包可以访问外层非全局作用域的变量,这个作用域称为 闭包作用域
【例1】闭包的类型及使用,可以看出i是函数类型

def funX(x):
    def funY(y):
        return x * y

    return funY


i = funX(8)
print(type(i))  # <class 'function'>
print(i(5))  # 40

注意:
(1)闭包的返回值通常是函数
【例子】实现一个计时器,
函数的作用是做一个计数器,

  • 用增加子函数 inc() 续一秒
  • 用减少子函数 dec() 废一秒
  • 用获取子函数 get() 看秒数
  • 用重置子函数 reset() 回原点
def make_counter(init):
    counter=[init]
    
    def inc():counter[0]+=1
    def dec():counter[0]-=1
    def get():return counter[10]
    def reset():counter[10]=init
    
    return inc,dec,get,reset

#初始化
inc, dec, get, reset = make_counter(0)
#续了3秒
inc()
inc()
inc()
#输出此时的秒数
dec()
#减去一秒,查看此时的秒数
print(get()) 
reset()
#重置并查看此时的秒数
print(get())  

结果为:

3
2
0

(2)如果要修改闭包作用域中的变量则需要 nonlocal 关键字
【例子】改变闭包作用域中的变量

def outer():
    num = 10

    def inner():
        nonlocal num  # nonlocal关键字声明
        num = 100
        print(num)

    inner()
    print(num)


outer()

# 100
# 100

 

9.递归

如果一个函数在内部调用自身本身,这个函数就是递归函数。
【例1】实现阶乘n!

def factorial(n):
    if n == 1:
        return 1
    return n * fact(n - 1)

【例2】实现斐波那契数列 f(n)=f(n-1)+f(n-2), f(0)=0 f(1)=1

def recur_fibo(n):
    if n <= 1:
        return n
    return recur_fibo(n - 1) + recur_fibo(n - 2)

求从0开始的11个斐波那契数列

lst=list()
for k in range(11):
    lst.append(recur_fibo(k))
print(lst)  

【例3】设置递归的层数,Python默认递归层数为 100

import sys
sys.setrecursionlimit(1000)

 

Lambda表达式

1.匿名函数的定义

在 Python 里有两类函数:

  • 第一类:用 def 关键词定义的正规函数
  • 第二类:用 lambda 关键词定义的匿名函数
    匿名函数的基本格式为
lambda argument_list: expression

其中

  • expression 中没有 return 语句,因为 lambda 不需要它来返回,表达式本身结果就是返回值
  • 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
    【例子】使用可变参数与匿名函数实现加法操作
func = lambda *args: sum(args)
print(func(1, 2, 3, 4, 5))  # 15

 

2.匿名函数的应用

函数式编程 是指代码中每一块都是不可变的,都由纯函数的形式组成。这里的纯函数,是指函数本身相互独立、互不影响,对于相同的输入,总会有相同的输出,没有任何副作用
【例1】函数式编程

def f(x):
    y = []
    for item in x:
        y.append(item + 10)
    return y

【例2】非函数式编程

def f(x):
    for i in range(0, len(x)):
        x[i] += 10
    return x

匿名函数常常应用于函数式编程的高阶函数 中,主要有两种形式:

  • 参数是函数 (filter, map)
  • 返回值是函数 (closure)

(1)匿名函数在filter函数中的应用
filter(function, iterable) 过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换
【例1】将匿名函数与filter函数结合,实现奇数的过滤

odd=lambda x:x%2==1 #如果x是奇数
templist=filter(odd,[1,2,3,4,5,6,7,8,9])
print(list(templist))
 # [1, 3, 5, 7, 9]

(2)匿名函数在map函数中的应用
map(function, *iterables) 根据提供的函数对指定序列做映射
【例2】

m1 = map(lambda x: x ** 2, [1, 2, 3, 4, 5])
print(list(m1))  
# [1, 4, 9, 16, 25]

m2 = map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
print(list(m2))  
# [3, 7, 11, 15, 19]

(3)匿名函数在自定义的高阶函数中的应用
除了 Python 这些内置函数,我们也可以自己定义高阶函数
【例3】

def apply_to_list(fun, some_list):
return fun(some_list)

lst = [1, 2, 3, 4, 5]
print(apply_to_list(sum, lst))
#15

print(apply_to_list(len, lst))
#5

print(apply_to_list(lambda x: sum(x) / len(x), lst))
#3.0



 

相关资料

  • https://www.runoob.com/python3/python3-tutorial.html
  • https://www.bilibili.com/video/av4050443
  • https://mp.weixin.qq.com/s/gKhXS8JVU8dZBHJF7sIFsw

练习题

1.怎么给函数编写⽂档?

在 def 语句后⾯把注释⽂档放在引号(单引、双引、三引都可以)⾥⾯就⾏,这个⽂档可以通过function.__doc__ 访问。

def square(x):
    """返回平⽅值"""
    return x*x
square.__doc__ ## '返回平⽅值'

2.怎么给函数参数和返回值注解?

代码执⾏时,注解不会做任何处理,只是存储在函数的 __annotations__ 属性(⼀个字典)中。
def function(text: str, max_len: 'int > 0' = 80) -> str:
函数声明中的各个参数可以在:之后增加注解表达式。如果参数有默认值,注解放在参数名和=号之间。如果想
注解返回值,在)和函数声明末尾的:之间添加->和⼀个表达式。
Python对注解所做的唯⼀的事情是,把它们存储在函数的 __annotations__ 属性⾥。 仅此⽽已,Python不做检
查、不做强制、不做验证,什么操作都不做。换句话说, 注解对Python解释器没有任何意义。注解只是元数
据,可以供IDE、框架和装饰器等⼯具使⽤。

3.闭包中,怎么对数字、字符串、元组等不可变元素更新。

使用 nonlocal 关键字

4.分别根据每一行的首元素和尾元素大小对二维列表 a = [[6, 5], [3, 7], [2, 8]] 排序。(利用lambda表达式)

使用sorted()函数实现 sorted(iterable, cmp=None, key=None, reverse=False)

  • iterable – 可迭代对象。
  • cmp – 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
  • key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse – 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
    参考https://www.runoob.com/python/python-func-sorted.html
#按首元素排序
a = [[6, 5], [3, 7], [2, 8]]
sorted(a, key=lambda x:x[0])
#按照尾元素排序
a = [[6, 5], [3, 7], [2, 8]]
sorted(a, key=lambda x:x[1])

5.利用python解决汉诺塔问题?
有a、b、c三根柱子,在a柱子上从下往上按照大小顺序摞着64片圆盘,把圆盘从下面开始按大小顺序重新摆放在c柱子上,尝试用函数来模拟解决的过程。(提示:将问题简化为已经成功地将a柱上面的63个盘子移到了b柱)
在这里插入图片描述

有n个盘子的汉诺塔步骤可以归纳为以下3步
(1)将1~n-1号盘子从a移动到b
(2)将n号盘子从a移动到c
(3)将1~n-1号盘子从b移动到c
在这里插入图片描述


def move(n,a,b,c):
    if n==0:
        return
    #如果n>1,a就要把n-1个盘子移动到b(可以经过c)
    move(n-1,a,c,b)
    #然后将剩下的n号盘子从a移动到c
    print('将%d号盘子从%s移动到%s'%(n,a,c))
    
    #最后将b上的n-1号盘子移动到c上
    move(n-1,b,a,c)
move(63,'a','b','c')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值