1 概述
函数是可重用代码块,功能最好比较单一
类型
内置函数,直接调用
标准库函数,import后调用
第三方库函数,社区提供,import后使用
自定义函数
示例
# 函数定义
def test():
print('*'*10)
print('@'*10)
# 函数调用
test()
print(id(test))
print(type(test))
要点
执行时创建函数对象,绑定到函数变量上(python中一切都是对象)
2 形参实参 | 文档字符串
三个单引号可定义多行字符串,在函数第一行可作为函数注释,称为文档字符串
# 形参
def printMax(a,b):
'''实现两个数字的比较'''
if a>b:
print(a)
else:
print(b)
# 实参
print(10,20)
print(30,5)
# 调用文档字符串
help(printMax.__doc__)
3 返回值
def my_avg(a,b):
# return还将结束函数的执行
return (a+b)/2
c = my_avg(10,20)
print(c)
# 带有返回值的函数可以直接作为值使用
print(my_avg(10,20)*10)
# 返回多个值,使用容器
def test02(x,y,z):
return [x*10,y*10,z*10]
print(10,20,30)
4 调用内存分析
调用函数时创建函数对象,堆中内存块,参数信息 | 代码信息
def test01():
print('Vincent')
# 函数对象赋给变量c
c = test01
c()
print(id(test01))
print(id(c))
5 变量作用域
全局变量
作用域为模块,降低函数的可读性
全局变量一般做常量使用
函数内部修改全局变量,需要用global声明
局部变量
仅限函数内部
# 测试全局变量\局部变量
# 定义全局变量
a = 3
def test():
# 定义局部变量
b = 4
global a
a = 300
# 打印局部变量
print(locals())
# 打印全局变量
print(globals())
print(a)
# 报错
print(b)
说明:
函数每次调用创建一个栈帧,栈帧中包含局部变量的引用
测试效率
局部变量与全局变量效率
import math
import time
def test():
start = time.time()
for i in range(1000000):
math.sqrt(30)
end = time.time()
print(end - start)
def test02():
start = time.time()
b = math.sqrt
for i in range(1000000):
b(30)
end = time.time()
print(end - start)
test()
test02()
5 参数传递
可变对象
python中参数传递都是引用传递
# 传递可变对象
b = [10,20]
def f2(m):
# m,b指向同一对象,修改m时直接修改b对象
m.append(30)
f2(b)
print(b)
不可变对象
# 传递不可变对象
# 数字\字符串\元组\布尔值等
a = 100
def f3(n):
# 修改时创建新对象,原对象不可变
n = n + 100
print(n)
f3(a)
print(a)
6 浅拷贝 | 深拷贝
浅拷贝
不拷贝子对象的内容,只拷贝子对象的引用
深拷贝
子对象的内存全部拷贝一份,对子对象的修改不改变原对象
# 测试深浅拷贝
import copy
a = [10,20,[5,6]]
# 浅拷贝
b = copy.copy(a)
# 深拷贝
# b = copy.deepcopy(a)
print(a)
print(b)
b.append(30)
# 修改列表中嵌套的列表
b[2].append(7)
# a列表中嵌套的列表也随之改变
print(a)
print(b)
传递不可变对象 - 浅拷贝
a = (10,20,[0,1])
print(id(a))
def test01(m):
print(id(m))
m[0] = 30
m[2][0] = 888
print(m)
print(id(m))
test01(a)
# 函数中改变m的值,由于m浅拷贝,a子对象内容改变
print(a)
7 参数几种类型
默认值参数
# 默认值参数必须位于普通参数后面
def f1(a,b=10,c=20):
print('{0}-{1}-{2}'.format(a,b,c))
f1(8)
f1(8,9)
命名参数
def f2(a,b,c):
print('{0}-{1}-{2}'.format(a,b,c))
# 根据参数名匹配,位置无关
f2(c=10,a=20,b=30)
可变参数
# 多个参数收入元组
def f1(a,b,*c):
print(a,b,c)
f1(8,9,10,20)
# 多个参数收入字典
def f2(a,b,**c):
print(a,b,c)
f2(8,9,name='Vincent',age=18)
强制命名参数
可变参数后边有参数必须强制命名
8 lambda表达式
简单的,同一行定义函数,生成一个函数对象
f = lambda a,b,c:a+b+c
print(f)
print(f(2,3,4))
# lambda表达式列表
g = [lambda a:a*2,lambda b:b*3,lambda c:c*4]
print(g[0](6),g[1](7),g[2](8))
9 动态改变代码 - eval
# eval可以动态改变代码结构
s = "print('abc')"
eval(s)
a = 10
b = 20
# eval中的代码可从外部传入
c = eval("a+b")
dict1 = dict(a=100,b=200)
d = eval("a+b",dict1)
print(d)
10 递归
自己调用自己的函数
需设置停止条件
def test01():
print('test01')
# 函数内部调用别的函数
test02()
def test02():
print('test02')
# 递归函数
def test03(n):
print('test01',n)
if n==0:
print('over')
else:
test03(n-1)
# 体会递归语句的执行顺序
print('test01***',n)
test03(4)
练习-递归求阶乘
def fn(n):
if n==1:
return 1
else:
return n*fn(n-1)
result = fn(5)
print(result)
扩展:
分形几何
10 嵌套函数
函数内部定义的函数
def f1():
print('f1')
def f2():
print('f2')
# 只能在f1中调用,可以通过内部函数的方式隐藏函数细节,还可以降低重复代码
f2()
f1()
# 练习:打印中英文名
def printName(isChinese,name,familyName):
def inner_print(a,b):
print('{0} {1}'.format(a,b))
if isChinese:
innerPrint(b,a)
else:
innerPrint(a,b)
11 nonLocal关键字
用来声明外部的局部变量
内部函数使用外部函数的变量时可用noLocal声明
a = 100
def outer():
b = 10
def inner():
# 内部函数可以直接使用外部函数的变量,但不能修改
print('inner:',b)
# 使用nonLocal声明后即可修改
nonLocal b
b = 20
global a
a = 1000
inner()
# 内层修改变量后,外层也被修改
print('outer',b)
outer()
print('a:',a)
12 LEGB规则
变量查找顺序:
Loca l-> Enclosed -> Globa l-> Built in
方法内 -> 嵌套 -> 全局 -> 内置
# 注掉此行,python会寻找内置函数str
str = 'global'
def outer():
# str = 'outer'
def inner():
# str = 'inner'
print(str)
inner()
outer()







网友评论