python函数基本知识

一,函数的内部底层结构
函数的变量名(标识符)存储在栈内存,其内放的位于堆内存中的函数信息的地址
所以说,有如下情况:

def fun():
    print('1')
fun()
c=fun
c()
print(fun)
print(id(fun))
print(c)
print(id(c))

结果为:

1
1
<function fun at 0x00000150CC062F78>
1446531968888
<function fun at 0x00000150CC062F78>
1446531968888

可以看出,print(fun)这条命令打印的就是对应堆内存内的地址。id(fun)同样对应的是堆内存中地址。变量没有地址。

二,变量的作用域
1,全局变量:在函数和类定义之外声明的变量,作用域为模块,它降低函数的通用性与可读性,尽量避免使用。函数中要改变全局变量的值,使用golbal声明。
2,局部变量:在函数体中声明的变量,若与全局变量重名,优先使用局部变量。
代码如下:

a=3
def text():
    b=4
    print(b)
    #print(a) #默认局部变量a,在下面会赋值a,所以有错误
    global a #在函数中改变全局变量
    a=300
    print(a)
    print(locals())#打印所有局部变量
    print(globals())#打印所有全局变量
text()
print(a)

结果如下:

4
300
{'b': 4}
{'__name__': '__main__', '__doc__': '\n@author: lhy\n@file: mypy09.py\n@time: 2020/02/29\n@desc:\n', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000020F29FE5A48>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/PycharmProjects/MyTest/mypy09.py', '__cached__': None, 'a': 300, 'text': <function text at 0x0000020F2A1E2F78>}
300

3,变量底层结构
局部变量的地址存放在栈帧中,栈帧在调用函数时创建,在调用结束后自动销毁,空间相对独立,所以内部可以调用全局变量,但是在函数外调用不了局部变量。栈帧中保存的是函数调用本次的信息。(从堆地址的内容中取出来?)

4,局部变量与全局变量效率测试
代码如下:

import time
import math
start=time.time()
def text():
    for i in range(10000000):
        math.sqrt(30)
text()
end=time.time()
print('耗时为{0}'.format(end-start))



start=time.time()
def text1():
    b=math.sqrt
    for i in range(10000000):
        b(30)
text1()
end=time.time()
print('耗时为{0}'.format(end-start))

结果如下:

耗时为2.0674610137939453
耗时为1.566443920135498

三,参数的传递
1,可变对象的传递:直接将a中id传给栈帧中形式参数m,两者指定同一地址,由于可变对象,所以直接修改。
2,不可变对象的传递:首先直接将a中id传给栈帧中形式参数m,两者指定同一地址,但是由于对象不可变,所以要改变m的值时,只能在堆中重新创建一个对象,并将新地址传给m。
代码如下:

a=[10,20]
print(id(a))
def text(m):
    print(id(m))
    m.append(30)
    print(id(m))
text(a)
print(a)

#不可变参数
a=100
print(id(a))
def text(m):
    print(id(m))
    m+=300
    print(id(m))
    print(m)
text(a)
print(a)

结果如下:

2395430277576
2395430277576
2395430277576
[10, 20, 30]
140725538500080
140725538500080
2395460236880
400
100

四,浅拷贝与深拷贝
浅拷贝:只拷引用,不拷内容。只不过指向同一地址。
深拷贝:全部拷贝(拷贝引用的引用)
代码如下:

#浅拷贝
import copy
a=[10,20,[5,6]]
b=copy.copy(a)
print(a)
print(id(a))
print(b)
print(id(b))
b.append(30)
b[1]=2
b[2].append(7)
print(a)
print(b)
print(id(a[1]))
print(id(b[1]))
print()



#深拷贝
import copy
a=[10,20,[5,6]]
b=copy.deepcopy(a)
print(a)
print(id(a))
print(b)
print(id(b))
b.append(30)
b[2].append(7)
print(a)
print(b)
print()

结果如下:

[10, 20, [5, 6]]
2707173823368
[10, 20, [5, 6]]
2707174317896
[10, 20, [5, 6, 7]]
[10, 2, [5, 6, 7], 30]
140725538497520
140725538496944

[10, 20, [5, 6]]
2430962695432
[10, 20, [5, 6]]
2433061442504
[10, 20, [5, 6]]
[10, 20, [5, 6, 7], 30]

由代码可以看出:深拷贝两个对象完全不相关。在浅拷贝中,b[1]=2,这条代码,意思是:本来a【1】,b[1],指向同一个对象,但是b修改了b【1】所以,a与b不同,但改变b【2】【1】就改变的是同一个目标。

注意以下程序:

a=(10,20,[5,6])
print(id(a))

def fun(m):
    print(id(m))
    #m[0]=30  #会报错
    m[2][1]=300
    print(id(m))
fun(a)
print(a)

结果为:

2707205833256
2707205833256
2707205833256
(10, 20, [5, 300])

在传递不可变对象时,如果不可变对象里包含可变对象,则在函数内修改这个可变对像,原对象也会改变。

五,参数的类型
1,位置参数
2,默认参数(默认参数一定要在普通参数后)
3,命名参数
4,可变参数(一个*为元组,两个为字典)
5,强制命名参数(带
的变量后加普通变量要用)
代码如下:

#位置参数与命名参数
def fun(a,b,c,d):
    print('{0}-{1}-{2}-{3}'.format(a,b,c,d))


fun(1,2,3,4)      #位置参数
fun(d=1,c=2,b=3,a=4)      #命名参数

#默认值参数
def fun1(a,b,c=20,d=30):
    print('{0}-{1}-{2}-{3}'.format(a,b,c,d))
fun1(1,2)
fun1(1,2,3)


#可变参数
def fun2(a,b,*c,**d):
    print('{0}-{1}-{2}-{3}'.format(a,b,c,d))


fun2(1,2,3,4,5,name='lhy',age=20)

结果如下:

1-2-3-4
4-3-2-1
1-2-20-30
1-2-3-30
1-2-(3, 4, 5)-{'name': 'lhy', 'age': 20}

六,lambda表达式声明匿名函数
lambda 变量:表达式

f=lambda a,b:print('***')
print(f)
print(f(1,2))


def test(a,b):
    print('**')
    return a+b

g=[lambda a,b:a*b ,test]
print(g[0](5,6),g[1](1,2))

结果如下:

<function <lambda> at 0x00000206FB3D6048>
***
None
**
30 3

注意,()代表引用,列表存储函数对象的用法

七,eval()函数
作用如下:

# eval
a='print(\'abcde\')'
eval(a)

d=10
e=20
f=eval('d+e')
print(f)

dict1=dict(d=100,e=200)
print(eval('d+e'))
print(eval('d+e',dict1))

结果如下:

abcde
30
30
300

八,递归函数
自己调用自己,应该包括终止条件与递归步骤

def fun1(n):
    print('第{0}次打印'.format(n))
    if n==0:
        print('over')
    else:
        fun1(n-1)
    print('*'*(n+1))
fun1(4)

结果:

4次打印
第3次打印
第2次打印
第1次打印
第0次打印
over
*
**
***
****
*****

这里要注意,调用后的打印顺序是从0-4

练习:使用递归算法计算阶乘

#用递归实现阶乘算法
def fun(n):
    if n==1:
        return 1
    else:
        return n*fun(n-1)

x=int(input("请输入计算的数字:"))
result=fun(x)
print(result)

结果为:

请输入计算的数字:5
120
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章