1.函数也是对象,内存底层分析
def:在堆里创建函数对象,同时在栈里创建对象—名字是函数名称,值为函数地址,进行调用时,函数名称(),表示调用函数,顺着地址找到函数进行调用,创建一次调用多次。当把函数对象赋给变量时,变量就会指向函数地址。
def t01():
print('dscvdsc')
t01()
c=t01
c()
print(id(t01))#1834710753776
print(id(c))#1834710753776
2.变量的作用域(全局变量和局部变量)
全局变量:作用域为定义的模块。(少定义)(作为常量)(函数内部想改变全局变量的值,使用global声明一下)
局部变量:作用域为函数体。在栈的栈帧中,调用完函数就删除。
#测试全局变量,局部变量
a=3#全局变量
def t01():
b=4
print(b*10)
global a
a=200
print(locals()) #局部变量
print(globals()) #全局变量
t01()
print(a)
3.局部变量和全局变量效率测试
局部变量的查询和访问速度比全局变量快,优先考虑局部变量。
#测试局部变量,全局变量的效率
import math
import time
def t021():
start=time.time()
for i in range(1000000):
math.sqrt(30)
end=time.time()
print('耗时{0}'.format(end-start))
def t022():
b=math.sqrt
start=time.time()
for i in range(1000000):
b(30)
end=time.time()
print('耗时{0}'.format(end-start))
t021()#耗时0.16359519958496094
t022()#耗时0.11869215965270996
4.参数的传递:从实参到形参的赋值操作。
所有的赋值操作都是”引用的赋值“,Python中参数的传递都是“引用传递”,不是“值传递”。
可变对象:字典、列表、集合、自定义的对象
#参数的传递
#可变对象
a=[10,20]
print(id(a)) #2263765414400
print(a)
def t01(m):
print(id(m)) #2263765414400与a指向同一个地址
m.append(30)
print(id(m)) #2263765414400
t01(a)
print(a) #[10, 20, 30]栈帧已经删除,但是a已经被改变
5.传递不可变对象
不可变对象:int、float、
a=100
def f1(n):
print("n:",id(n)) #n: 140737060942736
n=n+200 #创建新对象
print("n:",id(n)) #n: 2536025586064
print(n)
f1(a)
print("a:",id(a)) #a: 140737060942736
字符串、元组、布尔值,在赋值操作时会创建一个对象。
6.浅拷贝和深拷贝
浅拷贝:不拷贝子对象的内容,只拷贝子对象的引用。
深拷贝:会连子对象的内存全部拷贝一份,对子对象的修改不会影响源对象。
#测试浅拷贝,仅仅复制栈中的第一块地址内存,指向a中的内存
import copy
a=[10,20,[5,6]]
b=copy.copy(a)
print('a:',a) #a: [10, 20, [5, 6]]
print('b:',b) #b: [10, 20, [5, 6]]
b.append(30) #对a无影响
b[2].append(7) #对a有影响
print('浅拷贝.......')
print('a:',a) #a: [10, 20, [5, 6, 7]]
print('b:',b) #b: [10, 20, [5, 6, 7], 30]
def tdeepcopy():
#测试深拷贝,重新全部拷贝一份
a = [10, 20, [5, 6]]
b = copy.deepcopy(a)
print('a:', a) # a: [10, 20, [5, 6]]
print('b:', b) # b: [10, 20, [5, 6]]
b.append(30) # 对a无影响
b[2].append(7) # 对a无影响
print('浅拷贝.......')
print('a:', a) # a: [10, 20, [5, 6]]
print('b:', b) # b: [10, 20, [5, 6, 7], 30]
7.传递不可变对象,浅拷贝
#传递不可变对象时,不可变对象里面包含的子对象是可变的,则方法内修改了这个可变对象,源对象也发生变化
a=(10,20,[5,6])#元组不可变对象
print('a:',id(a)) #a: 2205237947008
def t01(m):
print('m:',id(m)) #m: 2205237947008
m[2][0]=888
print(m) #(10, 20, [888, 6])
print('m:',id(m)) #m: 2205237947008
t01(a)
print(a) #(10, 20, [888, 6])
8.参数的几种类型:位置参数、默认值参数、命名参数
#测试参数的类型:位置参数、默认值参数、命名参数
def t01(a,b,c,d):
print('{0}-{1}-{2}-{3}'.format(a,b,c,d))
def t02(a,b,c=10,d=20): #默认值参数必须位于其他参数后面
print('{0}-{1}-{2}-{3}'.format(a,b,c,d))
t01(1,2,3,4) #位置参数,个数必须一致
t01(d=20,b=40,a=1,c=2) #1-40-2-20 命名值参数,不再要求位置
t02(2,3,4) #2-3-4-20
9.可变参数(一个*为元组,**为字典)
强制命名参数(当带星号的“可变参数”后面增加新的参数,必须是强制命名参数)
#可变参数
def f1(a,b,*c): #c为元组
print(a,b,c) #8 9 (19, 20)
f1(8,9,19,20)
def f2(a,b,**c): #c为字典
print(a,b,c) #8 9 {'name': 'xiaohong', 'age': 18}
f2(8,9,name='xiaohong',age=18)
def f3(a,b,*c,**d):
print(a,b,c,d) #8 9 (30, 20) {'name': 'apple', 'age': 16}
f3(8,9,30,20,name='apple',age=16)
def f1(*a,b,c): #c为元组
print(a,b,c) #(8, 9) 19 20
f1(8,9,b=19,c=20)
10.lambda表达式和匿名函数
基本语法:
lambda arg1,arg2,arg3...:<表达式>
#测试lambda表达式,匿名函数
f=lambda a,b,c,d:a*b*c*d
print(f(2,3,4,5)) #120
g=[lambda a:a*2,lambda b:b*3]
print(g[0](6)) #12
11.eval()函数
#测试eval()函数
s="print('asdfg')" #asdfg必须是双引号
eval(s)
a=10
b=10
c=eval("a+b")
print(c) #20
dict1=dict(a=100,b=200)
d=eval("a+b",dict1)
print(d) #300
12.递归函数:在函数体内直接或者间接的自己调用自己。
(1)终止条件:表示递归什么时候结束,一般用于返回值,不再调用自己。
(2)递归步骤:把第n步的值和第n-1步相关联。
#测试递归函数的基本原理
def t01(n):
print('t01:',n)
if n==0:
print('over')
else:
t01(n-1)
print('t01****',n)
def t02():
print('t02')
t01(5)
#使用递归函数计算阶乘
def factorial(n):
if n==1:
return 1
else:
return n*factorial(n-1)
result=factorial(5)
print(result) #120