目录
-
函数的定义
# 函数的定义,注意冒号
def printMax(a, b): # 冒号
'''比较大小,输出大的值''' # 函数注释
if a > b:
print(a, "MAX")
else:
print(b, "MAX")
printMax(10, 20)
printMax(2, 1)
help(printMax.__doc__) # 双下划线,查看函数说明
--------------------------------
20 MAX
2 MAX
No Python documentation found for '比较大小,输出大的值'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.
--------------------------------
-
返回值
# 返回多个值需要用容器装好
def test(x, y, z):
return [x, y, z]
print(test(1, 2, 3))
-
函数是对象
函数作为对象,可以作为参数,也可以作为返回值
-
局部变量和全局变量
局部变量:在函数中使用
局部变量和全局变量同名时,在函数中隐藏全局变量,只使用局部变量
局部变量引用比全局变量快,尽量使用局部变量
全局变量:可以作为常数使用,作用于定义到模块结束
函数内改变全局变量的值,需要用 global 声明
a = 100 # 全局变量
def test():
b = 4
print(b*10)
# print(a) 这一句加上会报错,因为和全局变量重名,别认为是没有定义的局部变量
a = 200
print(a)
test()
print(a) # 全局变量没有改变
-----------------------------
40
200
100
-----------------------------
a = 100
def test():
global a # 修改全局变量
a = 200
test() # 必须要调用函数,才会修改全局变量
print(a)
测试局部全局变量的效率
import math
import time
def test01():
start = time.time()
for i in range(100000):
math.sqrt(30)
end = time.time()
print("time=",(end-start))
def test02():
b = math.sqrt # 全局变量变为局部变量
start = time.time()
for i in range(100000):
b(30)
end = time.time()
print("time=" ,(end-start))
test01()
test02()
---------------------------
time= 0.03200197219848633
time= 0.022001266479492188
---------------------------
-
参数的传递
Python 中所有的传递都是“引用传递”
对可变对象的传递
# 对于列表,字典,集合等可变对象
# 对可变对象进行写操作,直接作用于原对象
# 相当于利用 C 中的指针修改主函数变量的值
a = [10, 20]
print(a)
print(id(a))
def test(m):
print(id(m))
m.append(30)
print(id(m))
test(a)
print(a)
-----------------------------
[10, 20]
13583864 # 并没有产生新的对象
13583864
13583864
[10, 20, 30] # 原对象的值发生了变化
-----------------------------
对不可变对象的传递(不能改变不可变部分的值)
# 对于不可变对象,创建一个新的对象,把新的值给新对象
a = 100
print(a)
print(id(a))
def test(m):
print(id(m))
m = m + 200 # 创建了一个新的对象
print(id(m)) # 可以发现地址的变化
print(m)
test(a) # 这里传递的仍然是对象原地址
print(a)
------------------------
100
1680567008 # 刚开始 a 和 m 指向同一个对象
1680567008
5170976
300
100
------------------------
浅拷贝与深拷贝
浅拷贝:只是拷贝了子对象的引用,不拷贝子对象的内容,被拷贝的和拷贝出的指向同一个对象
深拷贝:不仅拷贝子对象引用,还拷贝子对象内容,指向拷贝出的内容
浅拷贝相当于克隆了一个人,没有克隆他的子孙
深拷贝把一个人的儿子孙子全克隆了
# 浅拷贝
import copy
a = [10, 20, [5, 6]]
b = copy.copy(a) # 拷贝出子对象 [10, 20, [5, 6]]
print("a:", a)
print("b:", b)
b.append(30) # 只修改了 b
b[2].append(7) # 两个都修改了
print("after copy------------")
print("a:", a)
print("b:", b)
-----------------------------------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
after copy------------
a: [10, 20, [5, 6, 7]]
b: [10, 20, [5, 6, 7], 30]
-----------------------------------------
# 深拷贝
import copy
a = [10, 20, [5, 6]]
b = copy.deepcopy(a) # 拷贝了全部,有了一个独立的大家庭
print("a:", a)
print("b:", b)
b.append(30)
b[2].append(7)
print("after deepcopy------------")
print("a:", a)
print("b:", b)
---------------------------------------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6]]
after deepcopy------------
a: [10, 20, [5, 6]]
b: [10, 20, [5, 6, 7], 30]
---------------------------------------------
对不可变对象中,可变子对象的内容可以在函数中发生变化
# 传递元组,元组中的列表元素内容可以修改
a = (10, 20, [4, 5])
print("a:", a)
def test(m):
print("m:", m)
m[2][1] = 50 # 不能修改整个 m[2]
m[2].append(6)
print("m:", m)
test(a)
print("a:", a)
-----------------------------
a: (10, 20, [4, 5])
m: (10, 20, [4, 5])
m: (10, 20, [4, 50, 6])
a: (10, 20, [4, 50, 6])
-----------------------------
m[2] = 5 会报错,这是对元组的操作
m[2].append(5) 这是对列表的操作
四种参数类型
# 位置参数,一一对应,个数不匹配会报错
def test(a, b, c):
print(a, b, c)
test(1, 2, 3)
#############################################################
# 默认值参数
def test(a, b, c, d = 20): # 默认值参数要放在位置参数后面,否则会报错
print(a, b, c, d)
test(1, 2, 3)
test(1, 2, 3, 4)
---------------------------
1 2 3 20 # 如果没有传递默认值参数,就使用初始化的默认值参数值
1 2 3 4 # 如果传递了,则使用传递的值
---------------------------
##############################################################
# 命名参数,在调用时通过形参名称对应
def test(a, b, c):
print(a, b, c)
test(1, 2, 3)
test(c=3, b=2, a=1)
-------------------------------
1 2 3
1 2 3
-------------------------------
###############################################################
# 可变参数,可变参数放到元组或字典中
def test(a, b, *c, **d): # * 元组 ** 字典
print(a, b, c, d)
test(1, 2)
test(1, 2, 3, 4)
test(1, 2, 3, 4, name="aaa", age=18)
--------------------------
1 2 () {}
1 2 (3, 4) {}
1 2 (3, 4) {'name': 'aaa', 'age': 18}
--------------------------
# 如果把可变参数放到前面,需要强制命名参数
def test(*a, b, c):
print(a, b, c)
test(1, 2, b=6, c=7) # b c 都要指明,不然会报错
----------------------------
(1, 2) 6 7
----------------------------
lambda 函数
# 第一种
f = lambda a, b, c: a + b + c
print(f(1,2,3))
# 第二种
g = [lambda a: a+5, lambda b: b*2, lambda c: c*3]
print(g[0](4))
# 相当于以下用法
def test01(a, b, c):
return a+b+c
def test02(a, b, c):
return a*b*c
h = [test01, test02]
print(h[0](1,2,3))
print(h[1](2,2,2))
----------------------------------------
6
9
6
8
----------------------------------------
eval 函数
# eval(source[,global,local]) global 只能是字典,global,local 可选
eval('print("abcd")')
a = 30
b = 10
c = eval("a+b")
print(c)
dict1 = dict(a = 300, b = 100)
d = eval("a+b", dict1) # 基本用法
print(d)
递归函数
def test(n):
print("test",n)
if n==0:
print("over")
else:
test(n-1)
print("test***", n)
test(4)
-----------------------------------
test 4
test 3
test 2
test 1
test 0
over
test*** 0 # 注意这里,函数在栈中的运行
test*** 1
test*** 2
test*** 3
test*** 4
-----------------------------------
首先打印一个 5 个 test ,接着 n 变为 0,运行最后一次递归的最后一步,打印 test***,最后一轮全部结束,进入倒数第二轮递归的最后一步,即 n=1······
# 实例,求阶乘
def f(n):
if n == 1:
return 1
else:
return n*f(n-1)
print( f(5) )
----------------------------------
120
----------------------------------
函数的嵌套
def f1():
print("f1 running...")
def f2():
print("f2 running...")
f2()
f1()
------------------------------------
f1 running...
f2 running...
------------------------------------
用于函数的封装(隐藏)、避免代码重复、闭包(见后面讲解)
# 小例子
# 原代码
def printchinesename(surname, firstname):
print("{0} {1}".format(surname, firstname))
def printforeignname(surname, firstname):
print("{0} {1}".format(firstname, surname))
printchinesename("爱", "学习")
printforeignname("Lu", "Yaoyi")
# 可以改成这样
def print_name(Ischina, surname, firstname):
def printname(a, b):
print("{0} {1}".format(a, b))
if Ischina:
printname(surname, firstname)
else:
printname(firstname, surname)
print_name(True, "爱", "学习")
print_name(False, "Lu", "Yaoyi")
nonlocal与global
用来声明全局变量和外部的局部变量,以便在函数内修改他们的值
a = 100
def f():
b = 10
def g():
nonlocal b # 注释掉,b 的值为 10
global a # 注释掉,a 的值为 100
a = 500
b = 50
g()
print("a:", a)
print("b:", b)
f()
------------------------------------------
a: 500
b: 50
------------------------------------------
LEGB规则
Python中查找名称的规则
L: Local 函数和类的内部
E: Enclosed 嵌套的上层函数
G: Global 模块中的全局变量
B: Build in Python 自带函数
全部查找不到就会报错,错误类型是未定义
注:基本常识