Python基础(函数)
使用def语句定义一个函数语法说明用来声明函数的关键字函数名,一个有效的标识符,规则和变量名一致。匈牙利命名法或驼峰法。形参,可以是0 ~ n 个,参数之间用逗号分隔。定义函数执行的具体操作。指定函数的返回值,没有则返回None,默认返回Nonereturn之后的代码不会执行。示例在add函数的return后面的print输出没有执行。
在数学中,函数(Function)是一个将每个元素从一个集合(定义域)映射到另一个集合(值域)的关系。
Function,英/ˈfʌŋkʃn/ n. 功能;函数;作用; v. 起作用;运转;正常工作
1. 基础认知
编程中的函数大抵如此,描述了一种“输入-输出”的关系。
1.1 函数的概念
概念
函数是可以重复执行的语句块,可以重复调用
作用
用于封装语句块,提高代码的重用性。
定位
函数是面向过程编程的最小单位
1.2 函数的定义
使用 def 语句定义一个函数
语法
说明
-
def:用来声明函数的关键字
-
function_name:函数名,一个有效的标识符,规则和变量名一致。匈牙利命名法或驼峰法。
-
parameters:形参,可以是0 ~ n 个,参数之间用逗号分隔。
-
函数体:定义函数执行的具体操作。
-
return:指定函数的返回值,没有则返回None,默认返回None
-
return之后的代码不会执行。
示例
在add函数的return后面的print输出没有执行
2. 内置函数
Python提供了大量的可直接使用的内置函数,主要执行一些常见的操作:数据处理、类型转换、数学计算、输入输出等。
2.1 all()
如果可迭代对象中的所有元素都为 True,返回 True,否则返回 False。
2.2 sum()
返回可迭代对象中所有元素的总和。
分析:可以是负数,可以有小数,可以是元组,可以是列表,int float这样的类型才能进行sum函数的运算
2.3 sorted()
返回一个新列表,其中包含可迭代对象中的元素,按照升序排序。

分析:lambda的基本用法: lambda 参数1, 参数2, ... : 表达式
在 Python 中,
lambda是一个关键字,用于创建匿名函数。匿名函数是一种没有名称的函数,通常用于需要一个简单函数的一次性场景。lambda函数的语法非常简洁,适合快速定义简单的操作。# 定义一个 lambda 函数,计算两个数的和
add = lambda a, b: a + b
print(add(3, 5)) # 输出:8所以上面的是读取字典中age键的值
2.4 reversed()
返回一个反向迭代器。
2.5 callable()
检查对象是否可以被调用(即是否是函数或方法)。
分析:自己定义的或者python自带的都可以调用callable的函数
2.6 zip()
将多个可迭代对象打包成一个元组,常用于并行遍历多个序列。
2.7 eval()
将字符串作为有效的 Python 表达式来执行,并返回结果。
eval(expression, globals=None, locals=None)
2.8 exec()
执行存储在字符串中的 Python 代码。
exec(object, globals=None, locals=None)
区别
返回值:
eval()返回表达式的结果,而exec()不返回任何值(返回None)。用途:
eval()用于计算表达式,而exec()用于执行代码块。安全性:
eval()和exec()都存在安全隐患,因为它们会执行任意代码。如果代码来自不可信的来源,可能会导致安全问题。
2.9 globals() 和 locals()
globals() 返回当前全局符号表(一个字典);locals() 返回当前局部符号表(也是字典)。
x = 10 print(globals()) # 输出: 包含全局变量的信息 print(locals()) # 输出: 包含局部变量的信息
2.10 filter()
从可迭代对象中过滤出符合条件的元素。
分析:filter的逻辑是,先通过形参1的函数来判断返回的结果是true还是false,如果是true,就将形参2的参数返回输出,传给新的对象x2.
2.11 map()
map(函数,可迭代对象) 传入两个参数: 函数和可迭代对象,返回一个经过函数筛选之后的可迭代对象

分析:可以看出来,map函数里面有两个形参,第一个形参是函数,第二个是来迭代的对象,把第二个形参里面的参数,传入到第一个形参函数里面,返回一个结果,然后让map函数来返回,赋值给新的对象x2
3.12 reduce()
reduce 是 Python 中的一个函数,用于对一个序列进行累积计算。它属于 functools 模块,在 Python 3 中不再是一个内置函数,因此需要先导入该模块才能使用。
reduce 函数会对序列中的元素依次应用一个函数,并将结果累积起来,最终返回一个单一的值。
from functools import reduce
reduce(function, iterable, initializer=None) 注意,如过没有给initializer赋值的话,累积将从序列的第一个元素开始。

分析:可以理解x1 + x2 ,这个函数是每次按顺序调用序列里的数据,经过形参一的函数计算返回一个新的值,作为下一次的x1加上序列表里第三个参数这个参数是x2,它们相加获得新的数作为x1加序列表里的第四个参数,依次类推,注意上述代码里是+,在实际情况也可能是乘法等自己定义函数方法,就把上面+的逻辑换成乘。
总结:前两个参数进行函数运算后得到结果,往后移动一位,得到的结果和新的一位进行函数运算再返回一个结果,再后移一位,依次类推
3. 函数的调用
函数名后面跟上 小括号() 表示函数的执行。
3.1 基本用法
语法
函数名(实际调用传递参数)
说明
函数调用是一个表达式,它可以参与运算
示例
3.2 调用传参
函数调用时传递参数的方式有多种,包括位置传参、关键词传参、多个参数解包、参数默认值等。
3.2.1 位置传参
最常见的传参方式,参数按定义的顺序依次传入函数,从左到右
示例:
3.2.2 关键词传参
通过指定参数的名称来传值,无顺序限制,代码可读性较高。
示例:
分析:因为是关键词的传参,顺序可以改变
3.2.3 参数默认值
定义函数时可为某些参数指定默认值,如果不传参则使用默认值。默认值参数必须位于无默认值参数的后面。
示例:
分析:按照形参顺序,依次传入数据,后面的有默认值的参数,可以不写
3.2.4 可变位置参数
使用 args可让函数接受任意数量的位置参数。args 会将多余的位置参数收集成一个元组。
示例:
结合使用
*args和**kwargs在同一个函数中,可以同时使用
*args和**kwargs,但它们必须按照顺序出现,即*args在前,**kwargs在后。

3.2.5 可变关键词参数
使用 kwargs 可以让函数接受任意数量的关键词参数。kwargs会将多余的关键词参数收集成一个字典。
示例:
分析:a传入的是位置参数,*是用来声明后面的都是关键词参数,它不是一个参数
3.2.6 多参数解包
Python 允许在调用函数时解包序列或字典,使其作为位置参数或关键词参数传递给函数,字符串也能解包,因为字符串是字符的序列
3.2.6.1 解包位置参数
使用 * 解包
3.2.6.2 解包关键词参数
使用 ** 解包
分析:用解包的方式,可以极大的简化代码,提高可读性
3.2.6.3 结合位置参数和关键词参数解包

分析:解包获得username,email键的值,刚好对应函数的参数名。解包完后剩下的键值对,放在**kwargs里面。就像是**user_info先执行解包的操作,得到username="alic123",email="alice@example.com" 这些
3.2.6.4 解包字典创建新字典

注意事项
字典的键必须是字符串:因为函数的参数名是字符串,所以字典的键必须是字符串类型。
参数名必须匹配:解包的字典中的键必须与函数的参数名匹配,否则会报
TypeError。默认参数:如果字典中没有提供某些参数,函数会使用默认值(如果有的话)。
3.2.7 参数混合使用
在函数调用时,可以混合使用位置参数和关键词参数,但位置参数必须放在关键词参数前面。
示例:

注意,如果要在一个函数里面同时传入很多参数的时候,有些是默认参数,在声明函数的时候,有默认参数的放在没有默认参数的后面,这样可以实现只给一部分参数传入参数,比如
跳过对b的传参
4. 可变和不可变参数
在 Python 中,实参可以是可变类型或不可变类型。它们的区别主要体现在值传递和引用传递的行为上。
4.1 不可变类型
不可变类型包括:int、float、str、tuple、frozenset 等。
传递方式是值传递: 传递给函数的是该对象的值,函数内部修改该值不会影响外部变量的值。
示例:
分析:在代码里,def的函数,是不会自己运行的,需要通过代码来调用,modify(a),在全局变量里声明了a=5,所以在调用函数里面,形参x的初始值就是a=5,改成10后,只是开辟了一个新的空间,存储了10这个int变量,然后让对象x指向它,5其实还在,a还是指向的5这个变量位置
4.2 可变类型
可变类型包括:list、dict、set 等。这些类型的对象可以在原地修改。
传递方式是引用传递 :传递给函数的是对象的引用(即内存地址),在函数内部修改该参数的内容会直接影响外部变量。
示例:
分析:可变类型,修改的时候,是在原来的数据上面进行修改,形参和全局变量都是指向的同一个地址,所以当在函数里面修改了lst对象,全局变量因为也是指向同一个地址,所以原始数据也变了
3.3 避免副作用
如果我真的想修改形参变量列表的值,但是又不影响全局变量的值,我应该怎么做呢?
通过复制对象来避免可变类型副作用:
列表:使用 lst.copy() 或切片 lst[:] 来创建一个副本。
字典:使用 dict.copy() 或 copy.deepcopy() 来进行深拷贝。
元组:推荐用tuple 创建新的元组,虽然本身就是不可变。
示例:
分析:先通过copy的函数,来复制一个新的字典或者列表,就是开辟了一块新的空间,来存储与全局可变变量只有地址不一样,里面的变量参数完全一样的列表或者字典,在函数里面就调用新复制的副本,这样就避免了全局变量的改变
5. 匿名函数
匿名函数是没有名字的函数,通常用于需要一个简短的、临时的函数场景,它可以有任意数量的参数,但只能包含一个表达式,并返回该表达式的结果。
5.1 基本语法
lambda arguments: expression
arguments:一个或多个输入参数,可以是位置参数或关键词参数。
expression:一个单一的表达式,它的值将作为返回值返回。
5.2 匿名函数定义
5.3 使用场景
lambda 函数常常与高阶函数如 map()、filter() 和 sorted() 等一起使用。
处理列表
分析:map函数是输出结果的,依次调用numbers这个列表里的数据,传递给lambda作为它的形参,执行表达式x**2,返回x**2这个结果,传递给squared_numbers列表
筛选列表
分析:filter函数只有当lambda返回的是true的时候,才输出x,当x%2!=0的时候,返回false,filter就不返回值
实现排序
分析:key是来排序的关键,可以是长度,大小,具体在上文中sorted函数有讲解
5.4 条件表达式
你可以在 lambda 函数中使用条件表达式(if-else)来做一些简单的决策。
分析:if - else 之间的表达式,是用来判断的,当返还值为true的时候,就输出if前面的结果,返回值为false的时候就输出else后面的结果 ,类似C语言里面 is_even=(x%2==0)?"Even":"Odd"
5.5 匿名函数优点
-
结构简单:
lambda函数通常用在需要一个短小函数的地方,而普通函数则更适合复杂的逻辑。 -
匿名性:
lambda函数是没有名字的,它们通常只在一个地方使用,并且不需要被重复调用。 -
功能限制:
lambda函数只能包含一个表达式,不可以包含多行语句,而普通函数可以包含多行代码、条件判断、循环等复杂逻辑。
6. 高阶函数
高阶函数是指可以接受一个或多个函数作为参数,或者返回一个函数作为结果的函数。
6.1 常见高阶函数
比较常用,单独拎出来熟悉一下
6.1.1 map
map(function, iterable)
map函数:
接受一个函数和一个可迭代对象
将接受的函数应用到可迭代对象的每个元素上
返回一个包含结果的迭代器
numbers = [1, 2, 3, 4, 5] squared = list(map(lambda x: x**2, numbers)) # squared现在包含[1, 4, 9, 16, 25]
6.1.2 filter
filter(function, iterable)
filter函数:
接受一个函数和一个可迭代对象
用接受的函数来筛选出可迭代对象中满足条件的元素
返回一个包含满足条件的元素的迭代器
numbers = [1, 2, 3, 4, 5] even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) # even_numbers现在包含[2, 4]
6.1.3 reduce
reduce(function, iterable[, initializer])
reduce函数:
reduce函数接受一个函数和一个可迭代对象
将接受的函数累积地应用到可迭代对象的元素上
可选的 $initializer$ 参数可以作为累积的初始值
from functools import reduce numbers = [1, 2, 3, 4, 5] product = reduce(lambda x, y: x * y, numbers) # product现在包含120 (1 * 2 * 3 * 4 * 5)
6.2 作为参数
高阶函数可以接受其他函数作为参数,用于自定义行为。
7. 变量作用域
变量的作用域(Scope)是指在程序中某个变量的有效范围,也就是在代码的哪个部分可以访问或修改该变量。作用域定义了变量的可见性和生命周期。
Python中的变量作用域遵循LEGB规则(Local, Enclosing, Global, Built-in),依次搜索变量的定义位置。
7.1 Local→局部作用域
指函数或方法内部定义的变量。
仅在函数内部有效,函数外部无法访问。
在函数调用时被创建,在函数调用后自动销毁。
示例:
分析:创建的局部变量x只能在func函数里面调用,在函数外面就找不到
7.2 Enclosing→嵌套作用域
指外层函数中的变量,在内层函数中可访问,但不可修改。
当一个函数嵌套在另一个函数内部时,外层函数的变量属于Enclosing作用域。
示例:
分析:虽然在全局变量里面声明了x = 10,输出还是 x = 20,因为访问顺序的原因
nonlocal:将局部作用域中变量声明为外部嵌套函数作用域中的变量
分析:在上述代码中,如果没有声明nonloacl a,虽然可以读取外部变量a,但当尝试改变外部变量a的时候,就会报错
7.3 Global→全局作用域
指模块级别定义的变量,整个模块都可以访问。
如果想在函数中修改全局变量,需要使用global关键字。
示例:如何用一个变量来记录一个函数调用的次数
7.4 Built-in→内建作用域
包含Python内建的函数、异常和常量,如print(), len(), int, Exception等。
这些变量可以在任何地方使用。
示例:
print(len([1, 2, 3])) # 使用内建函数len
7.5 变量查找顺序
作用域遵循LEGB规则(Local, Enclosing, Global, Built-in)
示例:
7.6 超越训练

分析:
题一:第一次返回的是fun(m,n=0),所以现在a的值是字典{"fun":lambda m:fun(m,0)},然后执行a["fun"](1)操作,可以得到,输出0,然后返回字典{"fun":lambda m:fun(m,1)},但是这个字典并没有转递给a,所以在后续的调用中,a还是={"fun":lambda m:fun(m,0)}*
None,0,0,0。
题二:这个是链式调用,首先是 fun(0),得到b=字典{"fun":lambda m:fun(m,0)},然后)["fun"](1)调用,返回的值是{"fun":lambda m:fun(m,1)},注意这样一步不像题一,这一步会把返回的结果赋值给b,然后调用["fun"](2),输出1,返回{"fun":lambda m:fun(m,2)},最后一步同理
输出None,0,1,2
题三:题一,题二的结合
输出None,0,1,1
8. 函数内存分配
1、将函数的代码存储到代码区,函数体中的代码不执行。
2、调用函数时,在内存中开辟空间(栈帧),存储函数内部定义的变量。
3、函数调用后,栈帧立即被释放。
def func(a, b):
a = 20
b[0] = 20
a = 10
b = [100]
func(a, b)
print(a) # 10
print(b) # [20]
9. 递归函数
递归是指函数直接或间接调用自身的过程。递归通常用于解决分解成相似子问题的复杂问题。
9.1 函数结构
递归函数通常由两个部分组成:
-
终止条件:用于确保递归能够停止,避免无限递归。
-
递归调用:函数在其内部调用自身,传递简化或减少的参数,以解决更小的子问题。
9.2 基本步骤
-
定义递归函数:在函数体内调用函数自身。
-
设定终止条件:确保递归能终止。
-
逐步简化问题:通过传递较小的参数递归求解,直至终止条件满足。
9.3 递归示例
递归:先递进,再回归。
9.3.1 阶乘定义
n! = n * (n-1) * (n-2) * ... * 1
递归公式:n! = n * (n-1)!,终止条件:0! = 1
示例代码:
def factorial(n): # 终止条件:n为0或1时,返回1 if n == 0 or n == 1: return 1 # 递归调用:n * (n-1)! return n * factorial(n - 1) # 测试 print(factorial(6)) # 输出 720
执行过程:
![]() |
![]() |
|---|---|
| 递归函数执行展开的过程 | 先递进,后回归 |
9.3.2 斐波那契数列
斐波那契数列(Fibonacci sequence)是一种经典的数列,它的特点是从第 3 项开始,每一项都等于前两项之和。前两项通常定义为:
F(0) = 0
F(1) = 1
从 F(2) 开始:
F(2) = F(1) + F(0) = 1 + 0 = 1
F(3) = F(2) + F(1) = 1 + 1 = 2
使用递归的思想实现斐波那契数列
参考代码:
def fibonacci(n): if n == 0: return 0 elif n == 1: return 1 else: return fibonacci(n - 1) + fibonacci(n - 2) print(fibonacci(8))
更多推荐












所有评论(0)