文章目录
一、函数
(一)分类
- 内置函数
- 标准库函数:通过import语句导入库,然后使用库中定义的函数
- 第三方函数
- 用户自定义函数
(二)核心要点
1.语法
def 函数名称([参数列表]}):
'''文档字符串''' #函数的注释。调用help(函数名._doc_)可以打印输出函数的文档字符串
语句/语句块
2.要点
python执行def时,会创建一个函数对象,并绑定到函数名变量上。
3.函数也是对象
def test():
print("hello")
test() #调用函数
c=test
c() #将test的内容赋值给c,此时调用c()的结果和test()一样
(三)参数
1.分类
参数可以划分为形参和实参两种
(1)含义
形式参数是在定义函数时使用的,不需要定义数据类型。
实参是在调用函数时,传递过去的。
(2)要点
- 圆括号内是形式参数列表,多个参数应用逗号隔开
- 无参数,也需要保留括号
- 实参列表必须与形参列表一一对应
2.参数的传递
(1)传递可变对象
- 可变对象有字典、列表和集合
- 传递可变对象时,原对象和形参指向同一个地址
- 对“可变对象”进行“写操作”,直接作用于原对象本身
(2)传递不可变对象
- 不可变对象有int、float、字符串、元组和布尔值
- 传递不可变对象时,原对象和形参指向同一个地址
- 在函数内对“不可变对象”进行修改,系统会创建一个新对象,此时原对象和新对象的地址不同
3.参数的类型
(1)位置参数
- 函数传递参数时,默认按照位置进行顺序传递
- 传递参数时,若个数不匹配,则报错
(2)默认值参数
- 为某些参数设置默认值
- 默认值参数通常放在位置参数的后面
def f1(a,b,c=10,d=20):
print(a,b,c,d)
f1(a=10,b=20)
(3)命名参数
按照形参的名称传递参数
def f2(a=10,b,c):
print(a,b,c)
f2(c=6,b=5)
(4)可变参数
- *param(一个星号),将多个参数收集到一个元组中
- **param(两个星号),将多个参数收集到一个字典中
>>>def f1(a,b,*c):
print(a,b,c)
>>>f1(8,9,19,20) #将19和20放到元组里
8,9,(19,20)
>>>def f2(a,b,**c):
print(a,b,c)
>>>f2(8,9,'name'='gao','age'=18) #将'name'='gao','age'=18放到字典里
8,9,{'name'='gao','age'=18}
(5)强制命名参数
在带星号的“可变参数”后面增加新的参数,必须是“强制命名参数”
>>>def f1(*a,b,c):
print(a,b,c)
>>>f1(2,b=3,c=5)
(2),3,5 #执行结果
(四)变量的作用域
- 局部变量
- 在函数体中声明的变量
- 局部变量的引用比全局变量快,应优先考虑使用
- 如果局部变量和全局变量同名,则函数内只能使用同名的局部变量
- 全局变量
- 在函数和类定义之外声明的变量
- 全局变量降低了函数的通用性和可读性,应尽量避免使用
- 在函数内修改全局变量,应使用global声明一下
(五)浅拷贝和深拷贝
- 内置函数:浅拷贝copy()、深拷贝deepcopy()
- 浅拷贝copy():不拷贝子对象的内存,只拷贝子对象的引用(只拷贝儿子,不拷贝孙子)
- 深拷贝deepcopy():拷贝子对象的内存,对子对象的修改不影响源对象(儿子孙子全拷贝)
(1)测试浅拷贝
import copy
a=[10,20,[5,6]]
b=copy.copy(a) #浅拷贝
print("a:",a)
print("b:",b) #输出结果一样
b.append(30)
print("a:",a) #输出结果为:[10,20,[5,6]]
print("b:",b) #输出结果为:[10,20,[5,6],30]
b[2].append(7) #因为浅拷贝没有拷贝孙子,所以修改时,是对原对象的孙子做出的修改
print("a:",a) #输出结果为:[10,20,[5,6,7]]
print("b:",b) #输出结果为:[10,20,[5,6,7],30]
(2)测试深拷贝
import copy
a=[10,20,[5,6]]
b=copy.deepcopy(a) #深拷贝
print("a:",a)
print("b:",b) #输出结果一样
b.append(30)
print("a:",a) #输出结果为:[10,20,[5,6]]
print("b:",b) #输出结果为:[10,20,[5,6],30]
b[2].append(7) #因为深拷贝拷贝了孙子,所以修改时,只对自己的孙子做出修改
print("a:",a) #输出结果为:[10,20,[5,6,7]]
print("b:",b) #输出结果为:[10,20,[5,6,7],30]
(3)不可变对象的子对象是可变对象,若修改可变对象,源对象也会发生改变
a=10
print("a:",a)
def test(m):
print("m",id(m))
m=20
print(m)
print("m",id(m)) #修改不可变对象,源地址会改变。是浅拷贝
test(a)
a=(10,20,[5,6]) #不可变对象中包含着可变对象
print("a:",a)
def test(m):
print("m",id(m)) #会输出(10,20,[888,6])
m[2][0]=888
print(m) #会输出(10,20,[888,6])
print("m",id(m)) #修改后,源地址不会改变。但是原对象和拷贝的对象的值都会改变
test(a)
(六)返回值
要点:
1.如果函数体中包含return语句,则结束函数的执行,并返回值
2.如果函数体中不包含return语句,则返回None值
3要返回多个返回值,使用列表、元组、字典、集合将多个值“存起来”即可
二、lambda表达式
- lambda表达式通常用来生成一个简单的函数。它只允许包含一个表达式,不能包含复杂语句,表达式的计算结果就是函数的返回值。
- 基本语法:lambda 参数1,参数2,…:表达式
f=lambda a,b,c:a+b+c
print(f(3,4,5))
f=[lambda a:a**2,lambda b:b**2,lambda c:c**2] #函数也是对象
print(f(2,3,4))
print(f[0](2))
三、eval()函数
- 功能:将字符串str当成有效的表达式来求值并返回计算结果
- 语法:eval(source[,global[,local]]) -> value
- 参数:①source:一个python表达式或函数compile()返回的代码对象;②
s= "print('abcde')"
eval(s)
a=10
b=20
c=eval("a+b")
print(c)
dict1=dict(a=10,b=20)
d=eval("a+b",dict1)
print(d)
四、嵌套函数
(一)使用情况
嵌套函数主要有以下三种优点:
① 封装-数据隐藏:外部无法访问“嵌套函数”
② 贯彻DRY(Don’t Repeat Yourself)原则:即避免在函数内部重复写代码
③ 闭包
def Printname(isChinese,name,familyname):
def inner_print(a,b): #inner_print就是嵌套函数
print("{0} {1}".format(a,b))
if isChinese:
inner_print(familyname,name) #这里体现了DRY原则
else:
inner_print(name,familyname)
printname(True,"心","何") #将会打印出何心
(二)nonlocal关键字
nonlocal 用来声明外层的局部变量
global 用来声明全局变量
a=100
def Outer():
b=10
def inner():
nonlocal b #声明外层函数的局部变量
print("inner:",b)
b=20
global a
a=1000
inner()
print("outer:",b)
outer()
print("a:",a)
(三)LEGB规则
python在查找名称时,是按照LEGB规则查找的:local–>Enclosed–>Global–>Built in
Local:指的就是函数或者类的方法内部
Enclosed:指的是嵌套函数(一个函数包裹着另一个函数,闭包)
Global:指的是模块中的全局变量
Built in :指的是python为自己保留的特殊名称。