目录
函数用法和底层分析
函数是可重用的程序代码块
函数分类
1.内置函数
可以拿来直接使用
2.标准库函数
使用import导入,使用其中定义的函数
3.第三方库函数
下载安装之后可以通过import导入
4.用户自定义函数
函数的定义和调用
def 函数名([参数列表]):
"文档字符串"
函数体/若干语句
1.python中执行def时会创建一个函数对象,并绑定到函数名变量上
2.参数列表:
(1)()内是形式参数列表,多个参数时用逗号隔开
(2)无参数也要保留括号
(3)实参列表必须与形参列表保持一致
(4)形参不需要声明类型,也不需要指定函数返回值类型
3.调用函数之前,必须先定义函数,先调用def创建函数对象
(1)内置函数对象会自动创建
(2)标准库和第三方库,import导入时会执行def语句
4.return返回值
(1)如果函数体中包含了return,则结束函数执行并返回值
(2)如果函数体中不包含return,则返回None值
(3)当有多个返回值时,用列表、元组、字典或集合将多个值存起来
(4)return有两个作用,一个是返回值,一个是结束函数执行
形参和实参
文档字符串
函数也是对象,内存底层分析
函数是对象,所以函数可以作为参数,也可以作为返回值
def test01():
print("abc")
test01() #函数后面加括号,表示调用函数
c=test01 #函数后面没有括号,表示把test01函数像参数一样传递给c对象
c() #调用函数c()
变量的作用域(全局变量和局部变量)
变量起作用的范围叫作用域
全局变量:
1.在函数和类定义之外声明的变量,作用域为定义的模块,从定义位置开始直到模块结束
2.全局变量降低了函数的通用性和可读性,尽量避免全局变量的使用
3.全局变量一般做常量使用
4.函数内要改变全局变量的值,用global声明一下
局部变量:
1.在函数体内(包括形参)声明的变量
2.局部比全局变量引用的快,在考虑效率较多和循环次数较多情况下,优先使用
3.如果局部和全局变量重名,在函数内隐藏全局变量,只使用局部变量
函数体中,locals() 输出所有局部变量,globals()输出所有全局变量
参数的传递
函数传递都是引用传递,就是说值都是存放在内存地址中,通过对象进行引用
传递可变对象引用
可变对象:字典、列表、集合、自定义的对象
对可变对象进行“写操作”,会直接作用于对象本身
b=[10,20]
def f2(m):
m.append(30)
f2(b)
此时b=[10,20,30]
id(b)和id(m)都是同一个内存地址,因为函数内部的m在函数引用时会产生一个栈帧,暂时存放m对象,而m对象在函数调用b对象时也暂时指向b的内存地址,从而继续执行append操作,在函数引用完成后栈帧会消失
传递不可变对象引用
不可变对象:数字、字符型、元组、函数、布尔值
对不可变对象进行“写操作”,会产生一个新的对象空间,用新的值填充这个空间(注意:如果是元组,对元组对象中的元素进行修改或者写操作,因为元组内部元素无法修改,会报错)
如果不可变对象包含了子对象是可变的,并且在函数内修改了这个可变对象,源对象也会发生变化
浅拷贝和深拷贝
浅拷贝:copy() 只拷贝对象第一次的内容,不拷贝子对象内容,只拷贝子对象引用。浅拷贝的对象如果有子对象,会把新拷贝的对象指向源对象的子对象
深拷贝:deepcopy() 会连子对象的内存一起拷贝,对子对象修改不会影响源对象,新对象和源对象是绝对独立的
参数的几种类型
位置参数:函数调用时,实参默认按照位置顺序传递,个数需要和形参匹配,按位置传递的参数称为位置参数
def f1(a,b,c):
...
f1(1,2,3)
默认值参数:在函数调用时,部分形参可以赋默认值,这些参数传递实参时可传可不传,位置必须在位置参数后面
def f1(a,b,c=10):
...
f1(1,2)
命名参数或者关键词参数:
def f1(a,b,c):
...
f1(c=3,a=1,b=2)
可变参数:可变数量的参数,一种情况“一个星号加参数(比如*c)”,会将*c所代替的多个参数放到一个元组中;另一种情况“两个星号加参数”,同理将多个参数放到字典中
强制命名参数:在可变参数后面加其他参数,这些其他参数必须是强制命名参数
def f1(*a,b,c)
...
f1(1,2,b=3,c=4)
如果写f1(1,2,3,4)会报错
lambda表达式和匿名参数
lambda表达式可以用来声明匿名函数,会生成一个函数对象
lambda arg1,arg2,arg3... : <表达式>
arg1,arg2,arg3函数参数,<表达式>函数体,运算结果是表达式的运算结果
f=lambda a,b,c:a+b+c
f(1,2,3)
6
g=[lambda a:a*2,lambda b:b*2]
g[0](1) #g[0]表示调用lambda a:a*2,(1)表示a=1
2
eval()函数
将字符串当作有效表达式来求值并返回结果
eval(source[,globals[,locals]]) -->>value
source: 表达式或者compile()返回的代码对象
globals:可选,必须是字典
locals:可选,任意映射对象
递归函数
函数体内部自己调用自己,必须包括两部分:
1.终止条件:
表示递归什么时候结束,一般用于返回值,不再调用自己
2.递归步骤:
把第n步的值和第n-1步相关联
举例:阶乘、分形几何
嵌套函数
作用:
1.封装,数据隐藏
2.降低重复代码
3.闭包
nonlocal关键字
在嵌套函数中,用来声明外层函数的局部变量
LEGB规则
查找名词时,按照LEGB规则查找
Local(函数或者类的方法内部)--->Enclosed(嵌套函数的外层)--->Global(模块的全局变量)--->Built in(python内置的特殊名称)
如果都没找到,就会产生一个NameError