前置疑问
Q1 什么是函数?函数如何定义? Q2 python中有哪几类函数? Q3 python中万物皆对象,函数底层分析是什么样子的? Q4 全局变量和局部变量的却别? Q5 参数传递内部原理是什么? Q6 lambda函数如何使用的?
学习内容
1、函数的定义、内存分析 2、参数的传递类型 3、lambda函数的使用 4、递归函数调用的底层原理 5、嵌套函数
学习时突发疑问
Q7 浅拷贝和深拷贝的原理?
学习产出
1、函数的使用
A1
1.1 什么是函数:
可重用的程序代码块,里面是一个功能的实现。
A2
1.2 函数的分类
- 内置函数
比如len()、str()、list()、dict()函数 - 标准库函数
比如turtle库函数,用import语句导入库,就可使用。 - 第三方函数
比如sklearn这个库,就为第三方库、用import语句导入 - 用户自定义函数
自己定义一个函数,实现一个小功能。
1.3 函数定义的格式:
def 函数名 ([参数1,参数2,参数3,...,]):
'''文档字符串函数的注释'''
语句块
[return 语句]
函数名书写规范需要满足标识符格式:全部用小写字母表示,多个单词之间用“_”下划线连接 比如func_name
1.4 格式语句的解释
-
参数 函数括号中可以有参数、也可以没有参数,称为形参。 调用函数时传递的函数是实参,实参的数量要等于形参的数量。 -
文档字符串 用来给一个函数做出解释,让使用者或者调用者知道这个函数干什么的 用help(func_name.doc)查看文档注释 -
return 若函数有返回值就用return。 return还可以用来表示函数结束。
A3
1.5 函数底层图解
def print_max(a,b): #有两个形参 a,b
''' 实现两个数的比较 返回较大的值'''
if a > b:
print(a)
else:
print(b)
print(id(print_max))
print_max(5,6)
A4
2、 全局变量和局部变量
a = 3
def func_02():
b = 30
print(b)
func_02()
当调用func_02函数时,会在栈里面生成一个stack frame 里面存储局部变量b的值,然后调用完之后该stack frame就会消失,再次调用,再次生成,如图所示:
全局变量在函数里面使用时,需要先赋值,否则默认为局部变量,为了识别全局变量,需要用global
a = 100
def outer():
b = 10
def inner():
nonlocal b #声明外层函数的局部变量
print("inner b:", b)
global a #声明全局变量
a = 200
inner()
print("outer b:",b)
outer()
- LEGB规则
L:local 函数或者类的内部方法 E:Enclosed 嵌套函数 G:Global 全局变量 B:Built in python中为自己保留的特殊名称
#测试LEGB
str = "global"
def outer():
str = "outer"
def inner():
str = "inner"
print(str)
inner()
outer()
#注释内部函数里的str
str = "global"
def outer():
str = "outer"
def inner():
#str = "inner"
print(str)
inner()
outer()
#注释外部函数的str
str = "global"
def outer():
#str = "outer"
def inner():
#str = "inner"
print(str)
inner()
outer()
#全局变量的str也注释
#str = "global"
def outer():
#str = "outer"
def inner():
#str = "inner"
print(str)
inner()
outer()
所以尽量声明局部变量,因为最先被调用,局部变量的效率比全局变量的效率高。
3、详解参数的传递
3.1 参数传递是什么意思
通俗来说,参数传递是实参与形参的赋值操作,python中“一切皆对象”,所以只有引用传递,没有值传递
A7
3.2 浅拷贝copy() 和深拷贝deepcopy()
源对象和副本之间存在联系,副本复制了源对象最外层容器,里面的元素是源容器中元素的引用,如果源对象中存在可变元素,则很容易发生意想不到的问题。比如一个列表[10,20,[5,6]]第三个元素就是可变的,下面用图来展示内存引用情况。
import copy
def test_copy():
'''测试浅拷贝'''
a = [10,20,[5,6]]
b = copy.copy(a)
print("a",a)
print("b",b)
b.append(30)
b[2].append(7)
print("{:*^20}".format("浅拷贝"))
print("a",a)
print("b",b)
test_copy()
图象由Python Tutor 网站产生
源对象和副本之间完全独立。
import copy
def test_deepcopy():
'''测试深度copy'''
a = [10,20,[5,6]]
b = copy.deepcopy(a)
print("a",a)
print("b",b)
b.append(30)
b[1] = 30
b[2].append(7)
print("{:*^20}".format("深度拷贝"))
print("a", a)
print("b", b)
test_deepcopy()
图象由Python Tutor 网站产生
A5
3.3 传递对象
- 传递可变对象
可变对象,比如列表、字典、集合。 传递的是对象的引用,在函数体中不用创建新的对象拷贝。
b = [10,20]
print("b:",id(b))
def func_01(m):
print("m:",id(m))
m.append(30)
func_01(b)
图象由Python Tutor 网站产生
- 传递不可变对象
虽然传递的还是对象的引用, 但传递的对象是不可变的,所以在函数体中,会新生成一个对象。
a = 100
print("a:",id(a))
def func_01(n):
print("n:",id(n))
n = n + 200
print("n:",id(n))
print(n)
func_01(a)
print(a)
a的值还是不变的。
- 传递不可变对象包含子对象是可变的
比如 (10,20,[5,6]) 一个元组是不可改变的,但是第三个元素是可变的,此时在传参的时候发生的浅拷贝
a = (10,20,[5,6])
print("a:",id(a))
def func_01(m):
print("m:",id(m))
m[2][0] = 56
m += (30,40)
print(m)
print("m:",id(m))
func_01(a)
print(a)
图象由Python Tutor 网站产生
3.4 参数的几种类型
- 默认值参数
在定义函数的时候给形参赋值了。默认值参数必须位于普通参数后面.
def func_01(a,b,c=100,d=200):
print(a,b,c,d)
func_01(10,20)
func_01(10,20,30)
func_01(10,20,30,40)
>>> def func_02(a,b,c):
print(a,b,c)
>>> func_02(c=100,b=200,a=300)
300 200 100
- 可变参数 数量可变
*param 收集多个参数放入元组中 **param 手机多个参数放入字典中
>>> def func_02(a,b,*c):
print(a,b,c)
>>> func_02(10,20,30,40,50)
10 20 (30, 40, 50)
>>> def func_03(a,b,**c):
print(a,b,c)
>>> func_03(10,20,name="A",age=20)
10 20 {'name': 'A', 'age': 20}
- 强制命名参数
可变参数在普通参数前面时,需要强制命名参数
>>> def func_04(*a,b,c):
print(a,b,c)
>>> func_04(10,20,30,b=30,c=40)
(10, 20, 30) 30 40
A6
4、lambda表达式和匿名函数
lambda表达式相当于一个简化的函数 格式:lambda arg1,arg2,arg3:<表达式>
>>> f = lambda a,b,c:a+b+c
>>> print(f)
<function <lambda> at 0x000001DA94E0C5E0>
>>> print(f(2,3,4))
9
>>> f = [lambda a:a*2, lambda b:b*3, lambda c:c*4]
>>> print(f[0](2),f[0](3),f[0](4))
4 6 8
5、递归函数
def func_01(n):
if n == 1:
return 1
else:
return n * func_01(n-1)
print(func_01(5))
6、嵌套函数(内部函数)
def func_01():
print("func_01")
def func_02():
print("func_02")
func_02()
func_01()
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,"ming","xiao")
printName(False,"Kruth","Bush")
什么时候使用嵌套函数? 1、封装 — 数据隐藏 外部无法访问"嵌套函数" 2、DRY原则(Don’t Repeat Yourself)原则 3、闭包
|