函数是对象+全局、局部变量+传参+浅/深拷贝+参数类型+lambda表达式和匿名函数+eval函数+递归函数+使用递归函数计算阶乘


一、函数也是对象

内存底层分析:

def test_01():
    print("love xidian")

test_01()
c = test_01  #把test_01的值赋予c
c()

print(id(test_01()))
#140716215539840
print(id(c()))
#140716215539840
#说明c()和test_01()是同一个对象

二、变量的作用域——全局变量和局部变量

a = 3  #全部变量

def test_01():
    b = 4   #局部变量
    print(b * 10)

    a = 300
    print(a)
    #300这里是局部的a

test_01()
#40
#在外面不能使用b,b仅限于在函数范围内使用

print(a)
#3  这里找到的是全局的a

(一)全局变量

1、全局变量:作用域为定义的模块,从定义位置开始直到模块结束;

2、全局变量降低了函数的通用性和可读性,应尽量避免全局变量的使用;

3、全局变量一般做常量使用;

4、函数内要改变全局变量的值,使用global声明一下

def test_01():
    b = 4   #局部变量
    print(b * 10)
    global a  # 在这里声明一下a是全局变量的a
    a = 300  #改变了全局变量的数值

test_01()
print(a)  #300,说明这里的global生效了

(二)局部变量:

1、在函数体中(包含形式参数)声明的变量;

2、局部变量的引用比全局变量快,优先考虑使用;

3、如果局部变量和全局变量同名,则在函数内隐藏全局

def test_01():
    b = 4   #局部变量
    print(b * 10)

    global a  # 在这里声明一下a是全局变量的a
    a = 300

    print(locals())  #打印输出局部变量
    print(globals()) #打印输出的全局变量

test_01()

#{'b': 4}
#{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001A0E5090880>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/developer_tools/python/pythonProject/课时76开始,函数对象测试+.py', '__cached__': None, 'test_01': <function test_01 at 0x000001A0E52D0310>, 'c': <function test_01 at 0x000001A0E52D0280>, 'a': 300}
#全局变量a的值变成了300

局部变量和全局变量的效率测试

#局部变量和全局变量的效率测试
def test_4():
    start = time.time()
    for i in range(1000000):
        math.sqrt(30)
    end = time.time()

    print("耗时:{0}".format(end - start))


def test_5():
    b = math.sqrt   #赋予函数的时候不需要带括号
    start2 = time.time()
    for i in range(1000000):
        b(30)
    end2 = time.time()
    print("耗时:{0}".format(end2 - start2))


#最后要调用的呀亲亲

test_4()   耗时:0.16280794143676758

test_5()   耗时:0.0753171443939209

三、参数的传递

从实参到形参如何赋值?python中的参数传递都是”引用传递“,不是“值传递”,具体操作分为两类:

1、对可变对象进行“写操作“,直接作用于原对象本身;可变对象有:字典、列表、集合、自定义的对象

#参数可变对象
a = [10, 30]
print(a)
print(id(a))   #1635259252800
print("***********************")

def test_1(m):
    print(id(m))      #把a传参之后,对象的地址没有发生变化# 1635259252800
    m.append(300)     #同理,对象的位置没有发生变化,只是在原来的基础上加了一个数值
    print(id(m))

test_1(a)
print(a)   #[10, 30, 300]

2、对”不可变对象“进行”写操作“,会产生一个新的”对象空间“,并用新的值填充;不可变的对象有:数字、字符串、元组、function

#传递不可变对象的引用
a = 100
print(id(a))   #140716654998400

def test_2(n):   #把a的值传到函数中时,n的值变为了a的值
    print(n)
    print(id(n))   #此时,n和a为同一个对象,所以id相同

    n = n + 200   #由于数值型是不可变的,所以产生了一个新的堆,id发生了变化
    print(id(n))  # 2047864663504
    print(n)

test_2(a)

四、浅拷贝和深拷贝

(1)copy(浅拷贝)

不拷贝子对象的内容,只拷贝对象的引用;

def testCopy():
    '''测试浅拷贝'''
    a = [10, 20, [5, 6]]
    b = copy.copy(a)

    print("a:", a)
    print("b:", b)

    '''
    a: [10, 20, [5, 6]]
    b: [10, 20, [5, 6]]
    '''
    b.append(40)
    b[2].append(7)

    print("浅拷贝***************************")
    print("a:", a)  # a: [10, 20, [5, 6, 7]]
    print("b:", b)  # b: [10, 20, [5, 6, 7], 40]

testCopy()

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

(2)deepcopy(深拷贝)

会连子对象的内存都全部拷贝一份

def testDeepCopy():
    '''测试深拷贝'''
    a = [10, 20, [5, 6]]
    b = copy.deepcopy(a)
    print("a:", a)
    print("b:", b)

    '''
    a: [10, 20, [5, 6]]
    b: [10, 20, [5, 6]]
    '''
    b.append(40)
    b[2].append(7)

    print("深度拷贝***************************")
    print("a:", a)  # a: [10, 20, [5, 6]]
    print("b:", b)  # b: [10, 20, [5, 6, 7], 40]

testDeepCopy()

当不可变对象中赋予了可变对象,那么,在函数传参的过程中改变了其中的可变对象时,源对象也发生了变化(地址发生了变动)
a = (10, 20, [5, 6])
#元组不可变,但列表可变
print("a:", id(a))
#a: 1771658326144
def test_yy(m):
    print("m:", id(m))   #m: 2784733593536
    m[2][0]=999
    print(m)   #(10, 20, [999, 6])
    print("m:", id(m))  #m: 1771658326144

test_yy(a)

五、参数的几种类型:


1、位置参数

从位置顺序传递,需要的个数和形参匹配,按照位置的参数传递

#位置参数
def f1(a,b,c,d):
    print("{0}-{1}-{2}-{3}".format(a, b, c, d))

f1(1, 2, 3, 4)
#1-2-3-4

2、默认值参数

可以为某些参数设置默认值,这些参数在传递时是可选的

#默认值参数
def f1(a, b, c= 10, d = 32):  #默认值参数必须位于普通位置参数后面
    print(a, b, c, d)

f1(8, 9)
#8 9 10 32

f1(8, 9, 19)
#8 9 19 32

def f1(a, b , c):
    print(a, b, c)

f1(8, 9, 10)
#8 9 10

3、命名参数,也称“关键字参数”

def f1(a, b, c= 10, d = 32):  #默认值参数必须位于普通位置参数后面
    print(a, b, c, d)

f1(a=10, b=20, c=50)
#10 20 50 32

4、星号多可变参数:

(1)一个星号,将多个参数收集到一个“元组”对象中;

#可变参数  *一个星是元组,两个星是列表
def f1(a, b, *c):
    print(a, b, c)

f1(8, 9, 10, 30, 40)
#8 9 (10, 30, 40) *之后是元组部分,可以有多个元素

  (2)两个星号,将多个参数收集到一个“字典”对象中。

def f2(a, b, **c):
    print(a, b, c)

f2(418, 24, name='littlestar', age= 19)
#418 24 {'name': 'littlestar', 'age': 19}

def f3(a, b, *c, **d):
    print(a, b, c, d)

(3)强制命名参数:

在带星号的“可变参数”后面增加新的参数,必须强制命名参数。

def f4(*a, b, c):
    print(a, b, c)
'''
f4(20, 30, 40, 50, 55)
会报错,因为不知道哪些元素属于a这个元组
TypeError: f4() missing 2 required keyword-only arguments: 'b' and 'c'
'''

f4(20, 30, 40, b=50, c=55)
#(20, 30, 40) 50 55

 六、lambda表达式和匿名函数

通常用于定义简单的函数,实际也是是生成了一个函数对象;lambda表达式只包含一个表达式,不能包含复杂语句

f = lambda a, b, c: a+b+c  #lambda的作用就是定义了一个函数
print(f)  #<function <lambda> at 0x000001C81C740280> 要传参进去
print(f(2, 3, 4))   #9

g = [lambda a: a * 2, lambda b:b * 3, lambda c: c * 4]
print(g[0](6), g[1](7), g[2](8))
#12 21 32  多个函数一起出现的时候,用列表的形式将他们组合到一起

def test_1(a, b, c, d):
    return a * b * c * d

h = [test_1,test_1]  #在这里调用函数的时候就不需要加括号了
print(h[0](1, 2, 3, 4))
#12 21 32

七、eval()函数 

eval("print('abcd')")
#abcd
#这里的字符串是可变的

s = "print('abcedf')"   #这里的s可以是用户提交的一个字符串
eval(s)
#abcedf

a = 10
b = 20
c = eval("a+b")
print(c)

dict1 = dict(a=100, b=200)
d = eval("a+b", dict1)   #这里直接定义了a和b 是dict1里面的数值
print(d)  #300

八、递归函数

递归函数是指:自己调用自己的函数

函数内调用其他函数
def test_01():
    print("test_01")
    test_02()


def test_02():
    print("test_02")

test_01()

test_01
test_02

递归函数基本原理

def test_01():
    print("test_01")
    test_01()
    print("######3##")

test_01()
#Process finished with exit code 1------表示异常,因为无限制得调用函数自己本身,栈空间满了

应该有一个停止的标志

真正的递归函数

def test_01(n):
    print("test_01:", n)
    if n == 0:
        print("over")
    else:
        test_01(n-1)

    print("test_01***", n)

test_01(5)

 九、使用递归函数计算阶乘

def factorial(n):

    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(8))
#40320

量,只是用同名的局部变量

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值