目录
1. 函数语法
def 函数名([参数列表]) :
'''文档字符串'''
函数体/若干语句
2. 要点
2.1 def 定义函数
Python 执行 def 时,会创建一个函数对象,并绑定到函数名变量上。
注:函数也是对象,执行def 定义函数后,系统就创建了相应的函数对象。
def print_star(n):
print("*"*n)
print(print_star)
print(id(print_star))
c = print_star
c(3)
'''
输出结果:
<function print_star at 0x000001E32AC7BA68>
2075186936424
***
注:
变量 c 和 print_star 都指向同一个函数对象。
因此,执行c(3)和执行print_star(3)的效果完全一致。
Python中,圆括号意味着调用函数;
若无圆括号,Python 则会将函数当做普通对象。
'''
2.2 参数列表
1. 圆括号内为形式参数列表,若有多个参数则使用逗号隔开;
2. 形式参数不需声明类型,也不需指定函数返回值类型;
3. 即使无参数,也必须保留空的圆括号;
4. 实参列表必须与形参列表一一对应。
2.3. return 返回值
1. 若函数体中包含 return 语句,则结束函数执行并返回值;
2. 若函数体中不包含 return 语句,则返回None 值;
3. 若需返回多个返回值,可使用列表、元组、字典、集合将多个值“存起来”。
2.4 文档字符串(函数的注释)
可在函数体内最开始的部分附上函数定义说明,通过三个单引号或三个双引号实现,中间可以加入多行文字进行说明。
3. 变量作用域
3.1 全局变量
1. 全局变量在函数和类定义之外声明,作用域为定义的模块,从定义位置开始直到模块结束;
2. 全局变量降低了函数的通用性和可读性,应尽量避免使用;
3. 全局变量一般做常量使用;
4. 若要在函数内改变全局变量的值,需使用 global 声明。
3.2 局部变量
1. 局部变量在函数体中(包含形式参数)声明;
2. 局部变量的引用比全局变量快,应优先考虑使用;
3. 若局部变量与全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量。
a = 100 #全局变量
def f1():
global a
print(a)
a = 300 #修改全局变量a
f1()
print(a)
def f2():
a = 3 #同名的局部变量
print(a)
f2()
print(a)
'''
输出结果:
100
300
3
300
'''
4. 参数传递
注:函数的参数传递,本质上是从实参到形参的赋值操作。Python 中参数的传递均为“引用传递”,而非“值传递”。
4.1 传递可变对象的引用
可变对象包括:字典、列表、集合、自定义的对象 等,对“可变对象”进行“写操作”,直接作用于原对象本身。
#传递可变对象的引用
a = [34,56]
def f2(m):
print("m:",m)
print("m的地址:",id(m))
m.append(375)
f2(a)
print("a:",a)
print("a的地址:",id(a))
'''
输出结果:
m: [34, 56]
m的地址: 2004856033672
a: [34, 56, 375]
a的地址: 2004856033672
'''
4.2 传递不可变对象的引用
不可变对象包括:数字、字符串、元组、函数 等,对“不可变对象”进行“写操作”,会产生一个新的“对象空间”,并用新的值填充这块空间。
#传递不可变对象的引用
a = 100
print("a的地址:",id(a))
def f3(n):
print("n的地址:",id(n))
n = n + 100
print("n的地址:",id(n))
print("n =",n)
f3(a)
'''
输出传递:
a的地址: 140726444731888
n的地址: 140726444731888
n的地址: 140726444735088
n = 200
'''
5. 浅拷贝 & 深拷贝
浅拷贝:不拷贝子对象的内容,只拷贝子对象的引用;
深拷贝:将子对象的内存也全部拷贝,对子对象的修改不会影响源对象。
#测试浅拷贝、深拷贝
import copy
def testCopy():
'''测试浅拷贝'''
a = [10,20,[5,6]]
b = copy.copy(a)
print("a:",a)
print("b:",b)
b.append(30)
b[2].append(7)
print("**************浅拷贝****************")
print("a:", a)
print("b:", b)
def testDeepCopy():
'''测试深拷贝'''
a = [10,20,[5,6]]
b = copy.deepcopy(a)
print("a:",a)
print("b:",b)
b.append(30)
b[2].append(7)
print("**************深拷贝****************")
print("a:", a)
print("b:", b)
testCopy()
print("**********************************")
testDeepCopy()
'''
输出结果:
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
**************浅拷贝****************
a: [10, 20, [5, 6, 7]]
b: [10, 20, [5, 6, 7], 30]
**********************************
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
**************深拷贝****************
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6, 7], 30]
'''
6. 不可变对象包含可变子对象
在函数中,若修改传递的不可变对象中包含的可变子对象,源对象也发生变化。
a = (10,20,[5,6])
print("a:",id(a))
def test01(m):
print("m:",id(m))
m[2][0] = 888
print(m)
print("m:", id(m))
test01(a)
print(a)
'''
输出结果:
a: 2203840772440
m: 2203840772440
(10, 20, [888, 6])
m: 2203840772440
(10, 20, [888, 6])
'''
7. 参数类型
7.1 位置参数
函数调用时,实参默认按位置顺序传递,需要个数和形参匹配。
7.2 默认值参数
可以为某些参数设置默认值,这些参数在传递赋值时可选。默认值参数必须放到位置参数后面。
7.3 命名参数
可以按照形参的名称传递参数。
#测试参数的类型:位置参数、命名参数、默认值参数
def test01(a,b,c,d):
print("a:{0}-b:{1}-c:{2}-d:{3}".format(a,b,c,d))
def test02(a,b,c=10,d=20): #默认值参数
print("a:{0}-b:{1}-c:{2}-d:{3}".format(a,b,c,d))
test01(1,2,3,4) #位置参数
test01(b=5,c=6,a=7,d=8) #命名参数
test02(15,5)
test02(15,5,35)
'''
输出结果:
a:1-b:2-c:3-d:4
a:7-b:5-c:6-d:8
a:15-b:5-c:10-d:20
a:15-b:5-c:35-d:20
'''
7.4 可变参数
即“可变数量的参数”:
1. *param(一个星号),将多个参数收集到一个“元组”对象中;
2. **param(两个星号),将多个参数收集到一个“字典”对象中。
3. 若在带星号的“可变参数”后面增加新的参数,则必须在调用的时候“强制命名参数”。
#测试可变参数、强制命名参数
def f1(a,b,*c,**d):
print(a,b,c,d)
f1(13,24,20,30,40,name='老白',age=26,job='waiter')
def f2(*a,b,c):
print(a,b,c)
f2(2,3,b=4,c=5)
'''
输出结果:
13 24 (20, 30, 40) {'name': '老白', 'age': 26, 'job': 'waiter'}
(2, 3) 4 5
'''
8. lambda 表达式
8.1 定义
lambda 表达式可以用来声明匿名函数,是一种简单的、在同一行中定义函数的方法,实际生成了一个函数对象。
lambda 表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
8.2 基本语法
lambda arg1,arg2,arg3... : <表达式>
其中:arg1/arg2/arg3 为函数的参数;<表达式>相当于函数体;运算结果为表达式的运算结果。
#测试lambda表达式
f = lambda a,b,c: a+b+c
print(f(4,5,6))
#效果相当于
def test01(a,b,c):
return a+b+c
g = [lambda a:a**2, lambda b:b**3, lambda c:c**4] #函数也是对象
print(g[0](2),g[1](3),g[2](4))
h = [test01,g] #函数也是对象
print(h[0](4,5,6),h[1][0](2))
'''
输出结果:
15
4 27 256
15 4
'''
9. 嵌套函数
即在函数体内部定义的函数(内部函数)。
#测试嵌套函数
def printName(isChinese,name,familyName):
def inner_print(a,b):
print("{0} {1}".format(a,b))
if isChinese:
inner_print(familyName,name)
else:
inner_print(name,familyName)
printName(True,"蘸糖","白")
printName(False,"George","Orwell")
'''
输出结果:
白 蘸糖
George Orwell
'''
10. nonlocal 关键字
作用类似于全局变量的 global 关键字,用来声明外层的局部变量。
#测试global、nonlocal关键字
a = 100
def outer():
b = 10
def inner():
nonlocal b
print("original nonlocal b:",b)
b = 20
global a
print("original global a:",a)
a = 200
inner()
print("updated nonlocal b:",b)
outer()
print("updated global a:",a)
'''
输出结果:
original nonlocal b: 10
original global a: 100
updated nonlocal b: 20
updated global a: 200
'''
11. LEGB 规则
Python 在查找“名称”时,按照 LEGB 顺序进行查找:Local-->Enclosed-->Global-->Built in
Local:函数或者类的方法内部;
Enclosed:嵌套函数;
Global:模块中的全局变量;
Built in:Python 保留的特殊名称;
如果一个名称在所有命名空间中都没有找到,则会产生一个NameError。