Python基础学习-函数
内存分析
#测试函数也是对象
def test():
print("wjwjwj")
test()
a=test
a()
print(id(test))
print(id(a))
print(type(a))
wjwjwj
wjwjwj
1567616045128
1567616045128
<class 'function'>
变量的作用域(全局变量和局部变量)
变量起作用的范围成为变量的作用域,不同作用域内同名变量互不影响。变量分为:全局变量,局部变量。
全局变量:
- 在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块结束。
- 全局变量降低了函数的通用性和可读性。应尽量避免全局变量的使用。
- 全局变量一般做常量使用。
- 函数内要改变全局变量的值,使用global声明一下。
局部变量:
- 在函数体中(包含形式参数)声明的变量。
- 局部变量的引用比全局变量快,优先考虑使用。
- 如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量。
#测试全局变量、局部变量
a=3 #全局变量
def r():
b=4 #局部变量
print(b)
global a #如果要在函数内改变全局变量的值,增加global关键字申明
a=10
r()
print(a)
4
10
全局变量与局部变量的效率测试
局部变量的查询与访问速度比全局变量快,优先考虑使用,尤其在循环的时候。
在特别强调效率的地方或者循环次数较多的地方,可以通过将全局变量转为局部变量提高运行速度。
@author: ramon
@file: function_6.py
@time: 2020/12/10
@desc:
"""
# 测试局部变量、全局变量的效率
#全局
import math
import time
def test1():
start=time.time()
for i in range(10000000):
math.sqrt(30)
end=time.time()
print("耗时{0}".format((end-start)))
#局部
def test2():
b=math.sqrt
start=time.time()
for i in range(10000000):
b(30)
end=time.time()
print("耗时{0}".format((end-start)))
test1()
test2()
耗时1.2386553287506104
耗时0.8766887187957764
参数的传递
- 可变对象有:字典、列表、集合、自定义的对象等。
- 不可变的对象有:数字、字符串、元组、布尔值、function等。
传递可变对象的引用
传递参数是可变对象,实际传递的还是对象的引用。在函数体中不创建新的对象拷贝,而是可以直接修改所传递的对象。
b=[30,60,90]
print(id(b))
print(b)
print("************************")
def test1(v):
print(id(v)) #b和m是同一个对象
v.append(900)#由于m是可变对象,不创建对象拷贝,直接修改这个对象
print(id(v))
test1(b)
print(b)
2815486677448
[30, 60, 90]
************************
2815486677448
2815486677448
[30, 60, 90, 900]
传递不可变对象的引用
传递参数是不可变对象,实际传递的还是对象的引用。在“赋值操作”时,由于不可变对象无法修改,系统会创建一个对象。
#传递不可变对象时,不可变对象里面包含的子对象是可变的。则方法内修改了这个可变对象,
a=(10,20,30,[6,8])
print("a",id(a))
def test(m):
print("m",id(m))
m[3][1]=10
print(m)
print("m",id(m))
test(a)
a 2308663109496
m 2308663109496
(10, 20, 30, [6, 10])
m 2308663109496
浅拷贝和深拷贝
为了更深入的了解参数传递的底层原理,我们需要讲解一下”浅拷贝和深拷贝”。我们可以使用内置函数:copy(浅拷贝)、deepcopy(深拷贝)。
浅拷贝:不拷贝子对象的内容,只是拷贝子对象的引用
深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响对象
b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
# 测试浅拷贝和深拷贝
#先引入模块
import copy
def testCopy():
'''测试浅拷贝'''
a=[10,20,[7.8]]
b=copy.copy(a)
print("a",a)
print("b",b)
print("测试1***************")
b.append(40)
b[2].append(10)
print("a",a)
print("b",b)
def testdeepCopy():
'''测试深拷贝'''
a=[10,20,[7.8]]
b=copy.deepcopy(a)
print("a",a)
print("b",b)
print("测试2***************")
b.append(40)
b[2].append(10)
print("a",a)
print("b",b)
testCopy()
print()
testdeepCopy()
a [10, 20, [7.8]]
b [10, 20, [7.8]]
测试1***************
a [10, 20, [7.8, 10]]
b [10, 20, [7.8, 10], 40]
a [10, 20, [7.8]]
b [10, 20, [7.8]]
测试2***************
a [10, 20, [7.8]]
b [10, 20, [7.8, 10], 40]
可变参数
**可变参数指的是"可变数量的参数"。分两种情况:
- *param(一个星号),将多个参数收集到一个“元组”对象中。
- **param(两个星号),将多个参数收集到一个"字典"对象中。
def test01(a,b,*c):
print(a,b,c)
test01(6,7,10,12)
def test02(a,b,**c):
print(a,b,c)
test02(15,16,name='yxy',age=28)
def test03(a,b,*c,**d):
print(a,b,c,d)
test03(20,21,91,92,94,name='yxy',age=28)
6 7 (10, 12)
15 16 {'name': 'yxy', 'age': 28}
20 21 (91, 92, 94) {'name': 'yxy', 'age': 28}
lambda 表达式和匿名函数
- lambda表达式可以用来声明匿名函数。lambda函数是一个简单的、在同一行中定义函数的方法。lambda函数实际生成了一个函数对象。
- lambda表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
基本语法如下:
lambda arg1 ,arg2,arg3…:<表达式>
arg1/arg2/arg3为函数的参数。<表达式>相当于函数体。运算结果是:表达式的运算结果。
#测试lambda表达式、匿名函数
x=lambda a,b,c,d:a*b*c*d
print(x(6,7,8,9 ))
#列表
y=[lambda a:a*5,lambda b:b*6,lambda c:c*7]
print(y[0](10),y[1](12),y[2](14))
3024
50 72 98
eval()函数的应用
#测试eval()函数
z="print('abcde')"
eval(z)
a=5
b=8
c=eval("a+b")
print(c)
#创建字典测试
dicts=dict(a=30,b=60)
y=eval("b/a",dicts)
print(y)
abcde
13
2.0
递归函数
递归函数就是:自己调用自己的函数,在函数体内部直接或间接的自己调用自己,总分为两个部分:
- 终止条件
- 表示递归什么时候结束。一般用于返回值,不再调用自己。
- 递归步骤
- 把第n步的值和第n-1步相关联。
#测试递归函数的基本原理
def test01(m):
print("test01:",m)
if m==0:
print("over!")
else:
test01(m-1)
print("test01***",m)
test01(5)
test01: 5
test01: 4
test01: 3
test01: 2
test01: 1
test01: 0
over!
test01*** 0
test01*** 1
test01*** 2
test01*** 3
test01*** 4
test01*** 5
阶乘练习
#使用递归函数,计算阶乘
def mathid(m):
if m==1:
return 1
else:
return m*mathid(m-1)
result=mathid(8)
print(result)