第五章 函数用法和底层分析
067-070函数简介
函数的基本概念
1)一个程序由一个个任务组成,函数代表一个任务或者一个功能
2)函数是代码复用的通用机制
函数的分类
1)内置函数
2)标准库函数:通过import语句导入库,从而使用其中的函数
3)第三方库函数
4)用户自定义函数<学习内容>
函数的定义和调用
核心要点
- 语法:
def 函数名([参数列表]):
'''文档字符串''' #相当于注释
函数体/若干语句
- 要点:
1)使用def定义函数,然后就是一个空格和函数名
2)参数列表:圆括号就是形参列表,有多个参数则使用逗号隔开;形参不需要声明类型,也不需要指定函数返回值类型;无参数必须保留空的圆括号;实参列表必须与形参列表一一对应。
3)return返回值:若函数体包含return语句,则结束函数执行并返回值;若函数体不包含return语句,则返回None值。
4)调用函数之前,必须先定义函数,即调用def创建函数对象:内置函数对象会自动创建;第三方库和标准库函数,通过import导入模块,会执行模块中的def语句。
形参和实参
- 形参在定义函数时使用,形参的命名只要符合标识符的命名规则即可。
文档字符串(函数的注释)
- 可通过三个单引号或者三个双引号实现,中间可加入多行文字进行说明。
- 通过调用help(函数名.doc)可以打印输出函数的文档字符串
返回值
- 若函数体包含return语句,则结束函数执行并返回值;
- 若函数体不包含return语句,则返回None值;
- 要返回多个返回值,使用列表、元组、字典将多个值存起来。
- 作用:1 返回值;2 结束函数的运行
函数也是对象,内存底层分析
071-072 变量的作用域(全局变量和局部变量)
- 变量的作用域:变量起作用的范围,不同作用域的同名变量之间互不影响,分为全局变量和局部变量。
- 全局变量:在函数和类定义之外声明的变量,作用域为定义的模块
-全局变量降低了函数的通用性和可读性,应避免使用
-全局变量一般做常量使用
-函数要改变全局变量的值,应使用global声明 - 局部变量:在函数体(包含形参)声明的变量
栈帧:stack frame,调用完会删除,用于储存局部变量 - 局部变量比全局变量访问速度快,可优先使用,特别是在强调效率的地方或者循环次数多的地方。
073-078 参数的传递
- python中参数的传递是“引用传递”而不是“值传递”,具体分为
-对可变对象进行“写操作”,直接作用于原对象本身<字典、列表、集合、自定义对象>
-对不可变对象进行“写操作”,会产生一个新的“对象空间”,并新的值填充对象空间<数字、字符串、元组、function>
传递可变对象的引用
- 传递参数是可变对象,实际传递的是对象的引用,在函数体中不能创建新的对象拷贝,而是可以直接修改所传递的对象
传递不可变对象的引用
- 传递参数是不可变对象,实际传递的是对象的引用,因为不可变对象无法修改,因此系统会创建一个新的对象。<int、float、字符串、元组、布尔值>
- 当不进行修改时,对象不发生变化。但是当对其进行修改,对象发生变化生成新的对象。
浅拷贝和深拷贝
- 浅拷贝和深拷贝是内置函数
- 浅拷贝copy():不拷贝子对象的内容,只拷贝子对象的引用
- 深拷贝deepcopy():会连子对象的内存也拷贝一份,对子对象的修改不会影响原对象
#测试浅拷贝和深拷贝
import copy
def testcopy():
‘’‘测试浅拷贝’‘’
a=[10,20,[5,6]]
b=copy.copy(a)
print("a:"a) #[10,20,[5,6]]
print("b:"b). #[10,20,[5,6]]
b.append(30)
b[2].append(7)
print("浅拷贝........")
print("a:"a) #[10,20,[5,6,7]]
print("b:"b) #[10,20,[5,6,7],30]
def testdeepcopy():
a=[10,20,[5,6]]
b=copy.deepcopy(a)
print("a:"a) #[10,20,[5,6]]
print("b:"b) #[10,20,[5,6]]
b.append(30)
b[2].append(7)
print("深拷贝........")
print("a:"a) #[10,20,[5,6]]
print("b:"b) #[10,20,[5,6,7],30]
- 传递不可变对象是浅拷贝·。对于不可变对象中包含可变对象,若修改其中可变对象,实际并未发生拷贝。
参数的形式
1)位置参数:函数调用时,实参按照位置顺序进行传递,个数与形参需要匹配,不匹配会报错。按照位置传递的参数即为“位置参数”。
2)默认值参数:将某些参数设置默认值的函数,称为默认值参数。默认值参数放在位置参数后面。若给默认值赋值则将默认值覆盖。
3)命名参数:关键字参数,即调用时写出形参对应的值。
4)可变参数:可变数量的参数
-可将多个参数收集到一个“元组”对象中。
-**可将多个参数收集到一个“字典”对象中
5)强制命名参数:在带星号的可变参数后新增加的参数,必须在调用时强制命名参数
079-08 一些相关函数的使用
lambda表达式和匿名函数
- lambda表达式用于声明匿名函数,是一种在同一行中定义函数的方法,实际上是生成了一个函数对象。lambda函数只允许包含一个表达式,不能包含复杂语句,表达式的计算结果就是函数的返回值。
- 语法:lambda arg1,arg2,arg3…:<表达式> 其中arg1,arg2,arg3为函数的参数,<表达式>相当于函数体
f=lambda a,b,c:a+b+c
print(f(1,2,3))
g=[lambda a:a*2,lambda b:b*3]
print(g[0](1),g[1](4))
eval()函数
- 功能:将字符串str当成有效的表达式来求值并返回计算结果
- 语法:eval(source[,golbals[,locals]])->value
- 参数:
-source:一个python表达式或函数compile()返回的代码对象
-golabls:可选,必须是dictionary字典
-locals:可选,任意映射对象
a="print('abcd')"
eval(a)
dict1=dict(a=10,b=20)
d=eval("a+b",dict1)
print(d)
递归函数
- 递归函数:在函数内部直接或间接的调用自身,由于递归函数会创建大量的函数对象、过量的消耗内存和运算能力,因此处理大量数据时因谨慎处理
#使用递归函数计算阶乘factorial
def factorial(n)
if n==1:
return 1
else:
n*factorial(n-1)
for i in range(1,6):
print(i,"!:",factorial(i))
嵌套函数
- 嵌套函数:即内部函数,在函数内部定义的函数
- 使用情况:
-封装-数据隐藏:外部无法访问嵌套函数
-贯彻DRY(don’t repeat yourself)原则:嵌套函数可以避免内部重复代码
-闭包
nonlocal关键字
- nonlocal:用来声明外层局部变量
- gobal:用来声明全局变量
def outer():
b=10
def inner():
nonlocal b
print('b:'b)
b=3
inner()
outer()
print('b:'b)
LEGB规则
- python查找名称是按照LEGB规则查找:local-enclosed-global-built in
-local:函数或者类的方法内部
-enclosed:嵌套函数(一个函数包裹一个函数,闭包)
-global:模块中的全局变量
-built in:python为自己保留的特殊名称 - name的查找:局部local命名空间-闭包enclosed作用空间-全局global命名空间-内建built in命名空间