• Python学习----Day08


    函数变量的作用域

    全局作用域

    • 全局作用域在程序执行时创建,在程序执行结束时销毁。
    • 所有函数以外的区域都是全局作用域。
    • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问。

    函数作用域

    • 函数作用域在函数调用时创建,在调用结束时销毁。
    • 函数每调用一次就会产生一个新的函数作用域(不调用不产生)。
    • 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问

    实例:全局变量、局部变量

    变量a是定义在testA函数内部的变量,在函数外部访问则立即报错。

    局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量。

    1. def testA():
    2. # 局部变量a
    3. # 在函数中为变量赋值时,默认都是为局部变量赋值
    4. # 局部变量不会影响函数外的变量。
    5. a = 100
    6. # 函数体内部访问,能访问到a变量
    7. print(a)
    8. testA() # 100
    9. print(a) # 报错:name 'a' is not defined

    全局变量,指的是在函数体内、外都能生效的变量

    1. # 定义全局变量a
    2. a = 100
    3. def testA():
    4. print(a) # 访问全局变量a,并打印变量a存储的数据
    5. def testB():
    6. print(a) # 访问全局变量a,并打印变量a存储的数据
    7. testA() # 100
    8. testB() # 100

    修改全局变量——global

           global 关键字的作用是,在函数内部声明一个变量为全局变量。换句话说如果希望在函数内部修改全局变量,则需要使用 global 关键字来声明变量。

    1. a = 100
    2. def testA():
    3. print(a)
    4. def testB():
    5. # 想要修改全局变量a的值是200
    6. # global 关键字声明a是全局变量
    7. global a
    8. a = 200
    9. print(a)
    10. testA() # 100
    11. testB() # 200
    12. print(f'全局变量a = {a}') # 全局变量a = 200

    注:如果在函数里面直接把变量 a=200 赋值,此时的 a 不是全局变量的修改,而是相当于在函数内部声明了一个新的局部变量。函数体内部修改全局变量: 先 global 声明 a 为全局变量,然后再变量重新赋值。

    函数注释

    函数说明的添加

    对函数说明的添加,可以通过”””对实现对函数的说明的添加

     函数的注释

    以上定义了名为my_function的函数,该函数有一个名为egg的参数,egg参数后面的“:str”是对该参数的注释,表示egg的类型是str,如图①所示。在函数参数列表与冒号之间的部分是对函数返回值的注释,如图②所示,表示my_function的返回值是str

    函数的值传递和引用传递

    Python 值传递和引用传递是根据实际参数的类型不同进行区分的,如下所示:

    • 值传递:指的是实参类型为不可变类型(数字、字符串、元组);
    • 引用传递(或叫地址传递):指的是实参类型为可变类型(列表,字典,set 集合,np矩阵,torch.Tensor矩阵)

    所谓值传递,通常就是拷贝参数的值,然后传递给函数里的新变量。这样,原变量和新变量之间互相独立,互不影响。 

    1. def modify_x(x):
    2. x = 99
    3. print("函数中修改过后的值: " , x)
    4. x=66
    5. modify_x(x)
    6. print("执行modify_x函数后的值:" , x)
    7. 在上述代码中,我们定义了一个变量x,并赋值为66
    8. 后将x传入其modify_x函数中,在函数中,我们将x赋值为99
    9. 打印一下函数中的x值,函数结果。 在主函数中再打印一下x的值

     

    所谓引用传递,通常是指把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内存地址。如果改变了其中任何一个变量的值,那么另外一个变量也会相应地随之改变。

    1. def modify_x(dict):
    2. dict["x"] = 99
    3. print("数中修改过后的值:" , dict)
    4. a={
    5. "x":66
    6. }
    7. modify_x(a)
    8. print("执行modify_x函数后的值:", a)
    9. 如上代码,我们定义了一个字典a,该字典有一个key为x,值为66
    10. 在调用modify_x函数中,我们将a传递给了函数,在函数中
    11. 我们将该字典key为x的赋值为99,函数结束,在主函数中打印a的值。

     

    匿名函数

    Python 使用 lambda 来创建匿名函数。

    所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数

    语法:lambda 参数:表达式 

    • 先写lambda关键字,然后依次写匿名函数的参数,多个参数中间用逗号连接,然后是一个冒号,冒号后面写返回的表达式。
    • 使用lambda函数可以省去函数的定义,不需要声明一个函数然后使用,而可以在写函数的同时直接使用函数。
    1. # 可写函数说明
    2. sum = lambda arg1, arg2: arg1 + arg2
    3. # 调用sum函数
    4. print ("相加后的值为 : ", sum( 10, 20 ))
    5. print ("相加后的值为 : ", sum( 20, 20 ))
    6. 运行结果
    7. 相加后的值为 : 30
    8. 相加后的值为 : 40

    使用场景:

    • 需要将一个函数对象作为参数来传递时,可以直接定义一个lambda函数(作为函数的参数或返回值)
    • 要处理的业务符合lambda函数的情况(任意多个参数和一个返回值),并且只有一个地方会使用这个函数,不会在其他地方重用,可以使用lambda函数
    • 与一些Python的内置函数配合使用,提高代码的可读性

     匿名函数与普通函数的对比

    1. def sum_func(a, b, c):
    2. return a + b + c
    3. sum_lambda = lambda a, b, c: a + b + c
    4. print(sum_func(1, 100, 10000))
    5. print(sum_lambda(1, 100, 10000))
    6. 运行结果
    7. 10101
    8. 10101

    lambda作为一个参数传递

    1. def sub_func(a, b, func):
    2. print('a =', a)
    3. print('b =', b)
    4. print('a - b =', func(a, b))
    5. sub_func(100, 1, lambda a, b: a - b)
    6. 运行结果
    7. a = 100
    8. b = 1
    9. a - b = 99

    我们可以将匿名函数封装在一个函数内,这样可以使用同样的代

    1. def myfunc(n):
    2. return lambda a : a * n
    3. mydoubler = myfunc(2)
    4. mytripler = myfunc(3)
    5. print(mydoubler(11))
    6. print(mytripler(11))
    7. 运行结果
    8. 22
    9. 33

    偏函数

    偏函数是固定一个函数的一些参数,然后生成一个新的函数的行为

    int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换。但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换。假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

    functools可以帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:

    1. >>> import functools
    2. >>> int2 = functools.partial(int, base=2)
    3. >>> int2('1000000')
    4. 64
    5. >>> int2('1010101')
    6. 85

    函数的嵌套

    通过将函数定义在已存在的函数内容,称为:嵌套函数

    实例:

    1. def func1():
    2. print('this is func1')
    3. def func2(): # 此函数为嵌套函数
    4. print('this is func2')

    注意:这里要注意的是我们无法在外部函数外直接调用内部函数

    调用嵌套函数

    1. def func1():
    2. print('this is func1')
    3. def func2():
    4. print('this is func2')
    5. func2() # 通过在同级别位置调用这个函数
    6. func1()
    7. def func1():
    8. def func2():
    9. print('this is func2')
    10. return func2 # 调用func1 将func2函数对象返回给调用者
    11. res = func1() # 调用func1,返回了func2的返回对象
    12. # res = func2
    13. res() # 调用的就是func2
    14. 打印结果:'this is func2'

    闭包

    闭包定义:

            在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包

    必报的构成条件:

    • 在函数嵌套(函数里面在定义函数)的前提下
    • 内部函数使用了外部函数的变量(还包括外部函数的参数)
    • 外部函数返回了内部函数

    闭包书写步骤:

    • 定义外部函数
    • 定义外部函数,在内部函数中使用外部函数的变量
    • 外部函数返回内部函数的地址
    1. # 闭包函数的实例:outer()是外部函数,a和b都是外部函数的临时变量
    2. def outer(a):
    3. b = 10
    4. # inner()是内部函数
    5. def inner():
    6. # 在内部函数中用到了外部函数的临时变量
    7. print(a+b)
    8. # 外部函数返回值是内部函数的引用
    9. return inner
    10. # 调用外部函数,传入参数5。此时外函数两个临时变量a是5 b是10,并创建了内部函数,然后把内部函数的引用返回给了demo进行存储,外部函数结束的时候发现内部函数将会调用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
    11. demo1 = outer(5)
    12. # demo存储了外部函数的返回值,也就是inner()函数的引用,这里相当于执行inner函数
    13. demo1() # 15
    14. demo2 = outer(7)
    15. demo2() # 17

    修改闭包变量   

      在内部函数中想修改闭包变量(外部函数绑定给内部函数的局部变量)时:Python3中,可以使用nonlocal关键字声明一个变量,表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量

    1. # 修改闭包变量实例
    2. def outer(a): # outer是外部函数,a和b都是外部函数的临时变量
    3. b = 10 # a和b都是闭包变量
    4. c = [a] # 这里对应修改闭包变量的方法2
    5. def inner(): # inner是内部函数
    6. # 内函数中想修改闭包变量
    7. nonlocal b # 方法1 nonlocal关键字声明,此处的b是outer()函数中的b
    8. b += 1 # b=11
    9. c[0] += 1 # 方法2 把闭包变量修改成可变数据类型,比如:列表
    10. print(c[0], b)
    11. return inner # 外部函数返回内部函数的引用
    12. demo = outer(5)
    13. demo() # 6 11
    • Python3中,可以使用nonlocal关键字声明一个变量,表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量
    • 在内部函数中声明变量b,如果我们不加nonlocal关键字,那么我们取到的b就不是外部函数中定义的b

    装饰器 

            装饰器是给现有的模块增添新的小功能,可以对原函数进行功能扩展,而且还不需要修改原函数的内容,也不需要修改原函数的调用

    作用:不改变原有函数的前提下,为函数添加新的功能模块,但是源代码没有改变

    1. def guanjia(fun):
    2. def inner():
    3. print("123")
    4. fun()
    5. print("456")
    6. return inner()
    7. @guanjia
    8. def play1():
    9. print("静安寺大家")
    10. @guanjia
    11. def play2():
    12. print("案说法")
    13. guanjia(play1)
    14. guanjia(play2)
    15. print(play1())
    16. print(play2())
    17. 123
    18. 静安寺大家
    19. 456
    20. None
    21. 123
    22. 案说法
    23. 456
    24. None

    装饰器雏形:

    1. def fun(目标函数):
    2.     def inner():
    3.         之前添加的值
    4.         目标函数原函数执行
    5.         之后添加的事情
    6.     return inner
    7. @fun    #目标函数 = fun (没目标函数)
  • 相关阅读:
    程序环境与预处理笔记
    uniapp微信小程序获取屏幕宽高
    dubbo分布式日志调用链追踪
    leetcode692:前K个高频单词
    Java中级——lambda表达式
    stm32通过AT指令与esp8622通信
    和平精英中传群岛怎么进 和平精英中传群岛进入攻略
    【Java多线程】ThreadLocal内存泄露问题
    2024年热门电脑监控软件,十大电脑监控软件推荐
    工业设计|设计就是生活
  • 原文地址:https://blog.csdn.net/weixin_74227828/article/details/133844967