函数内存底层分析
函数也是对象
局部变量和全局变量(变量的作用域)
作用域:变量起作用的范围,不同作用域内同名变量之间相互不影响
全局变量:
在函数和类定义之外声明的变量,作用域为定义的模块,从定义位置开始直到模块结束
降低了函数的通用性和可读性,应尽量避免
一般做常量使用
函数内部改变全局变量的值要用global声明
局部变量:
在函数体中包含形式参数声明的变量
局部变量的引用比全局变量快,优先考虑使用
如果全局变量和局部变量同名,则在函数内隐藏全局变量,只使用同名的局部变量
局部变量和全局变量测试
a=3 #全局变量
def func01():
b=4 #局部变量
print(a) #会报错,因为没有局部定义这个a是什么
print(b*10)
a=300
print(a) #不会报错,返回值为300,这和上面的全局变量a不是同一个
global a #声明这里的a是全局变量的a
a=300 #将全局变量的a改为300
print(a)#这个返回的结果依旧时全局变量a的结果,因为此时没有调用函数func01
a=3 #全局变量
def func01():
b=4 #局部变量
print(a) #会报错,因为没有局部定义这个a是什么
print(b*10)
a=300
print(a) #不会报错,返回值为300,这和上面的全局变量a不是同一个
global a #声明这里的a是全局变量的a
a=300 #将全局变量的a改为300
print(a)#这个返回的结果和上面的代码不同因为在函数里声明了改变全局变量a为300,所以这里返回的值为300
局部变量和全局变量效率测试
自定义的函数的名称也是全局变量
import math
import time
def func01():
start=time.tiem()
for i in range(1000000):
math.sqrt(30) #全局变量
end=time.tiem()
print('耗时{0}'.format((end-start)))
def func02():
start=time.tiem()
b=math.sqrt
for i in range(1000000):
b(30) #局部变量
end=time.tiem()
print('耗时{0}'.format((end-start)))
func01()
func02() #测试结果耗时小于func01
参数的传递
本质上是实参到形参的赋值操作,python中一切皆对象,所有的赋值操作都是‘引用的赋值’,所以python中的参数传递都是‘引用传递’(将对象的地址传递给变量,再通过地址去找value),不是值传递
传递可变对象
从实参到形参的赋值
a=[10,20]
print(id(a))
print(a)
def func01(m)
print(id(m)) #地址和a的一样
m.append(300)
print(id(m)) #序列为可变对象,改变了序列但是没有改变地址
func01(a)
print(a) #a的值发生改变
传递不可变对象
看起来像值传递
a==100
print(id(a))
print(a)
def func01(m)
print(id(m)) #这里的地址还和全局变量a的一样
m+=100
print(id(m)) #因为数字对象不可变所以重新产生了一个值为300的对象,地址发生改变
func01(a)
print(a) #全局变量a的值未发生改变
深拷贝和浅拷贝
浅拷贝
import copy
def testcopy():
a=[10,20,[5,6]]
b=copy.copy(a)
print('a:'a)
print('b:'b)
#对b做出改变
b.append(30)
b[2].append(7)
print('a:'a)
print('b:'b)
testcopy()
深拷贝
import copy
def testdeepcopy():
a=[10,20,[5,6]]
b=copy.deepcopy(a)
print('a:'a)
print('b:'b)
#对b做出改变
b.append(30)
b[2].append(7)
print('a:'a)
print('b:'b)
testdeepcopy()
参数的类型
位置参数
def f(a,b,c) #根据位置来一一匹配
print(a,b,c)
f(2,3,4)
f(2,3)
默认值参数
def f(a,b,c=10,d=16) #默认值参数要跟在普通位置参数后面
print(a,b,c,d)
f(2,3) #根据位置来一一匹配
f(2,3,4) #传递新值时原来的默认值被替换
命名参数
def f(a,b,c)
print(a,b,c)
f(2,3,4)
f(a=10,c=13,b=16) #位置不一定要和上面的形式参数一一对应
可变参数
*a,将多个参数收集到一个元组对象中
def f(a,b,*c):
print(a,b,c)
f(1,2,3,4,5)
返回结果:
1,2,(3,4,5)
** a,将多个参数收集到一个字典对象中
def f(a,b,**c):
print(a,b,c)
f(1,2,name='vivi',age=18)
返回结果:
1,2,{‘name’:‘vivi’,‘age’:18}
强制命名参数
def f(*a,b,c):
print(a,b,c)
f(1,2,3,4,5) #分不清是都给到a还是怎样,所以报错
f(1,2,3,b=4,c=5)
返回结果:
(1,2,3),4,5
lambda表达式和匿名函数
简单的在同一行中定义函数的方法,实际生成一个函数对象
只允许包含一个表达式,不能包含复杂语句,表达式的计算结果就是函数的返回值
语法结构:
lambda arg1,arg2,arg3…: <表达式>
arg1,arg2,arg3为函数的参数
g = lambda a,b,c: a+b+c
print(g)
print(g(3,4,5))
def f(a,b,c):
return a+b+c
print(f)
print(f(2,3,4))
def j(a,b,c):
print(a+b+c)
j(1,2,3)
返回结果:
<function < lambda> at 0x0000003B3EB0C1E0>
12
<function f at 0x0000003B3EDE22F0>
9
6
g= [lambda a:a*2,lambda b:b*3]
#调用函数
print(g[0](3),g[1](2))
def f(a):
return a*2
def k(b):
return b*3
h=[f,k]
print(h[0](3),h[1](3))
print(f(3),k(2))
返回结果:
6 6
6 6
6 6
eval()函数
将字符串str当成有效的表达式求值并返回计算结果
语法结构:
eval(source[,globals[,locals]]) → value
source:一个python表达式或函数,compile()返回的代码对象
globals:可选,必须是dictionary
locals:可选,任意映射对象
递归函数
自己调用自己的函数,在函数体内直接或间接的调用自己
def f(n):
print('f':n)
if n ==0:
print('over')
else:
f(n-1)
print('f***',n)
f(2)