• Day 08 python学习笔记


    函数


    作用域

    作用域:变量的访问权限

    全局变量与局部变量

    声明在函数外边的变量----全局变量        ----》全局作用域
    函数内部的变量------局部变量                ----》局部作用域
    顶格创建的函数也是全局的

    1. 例:
    2. a = 100
    3. def test_01():
    4. a = 0
    5. b = 110
    6. print(a)
    7. print(b)
    8. test_01() #都是局部变量里的
    9. print(a) #全局变量的a
    10. print(b) #报错,因为b变量是局部变量,无访问权限
    11. 结果:
    12. 0
    13. 110
    14. 100
    15. Traceback (most recent call last):
    16. File "D:python\Day08\代码\02-函数中变量的作用域.py", line 19, in
    17. print(b)
    18. NameError: name 'b' is not defined

    注意:局部的东西,一般都是局部自己访问使用的

    但全局变量都可访问

    1. 例:
    2. a = 100
    3. def test_02():
    4. print(a)
    5. test_02()
    6. 结果:
    7. 100

    扩展:

    函数内部可以使用全局变量但是无法修改全局变量

    1. 例:
    2. a = 100
    3. def test_03():
    4. a += 100 #报错,函数内部可以使用全局变量但是无法修改全局变量
    5. print(a)
    6. test_03()
    7. 结果:
    8. Traceback (most recent call last):
    9. File "D:\python\Day08\代码\02-函数中变量的作用域.py", line 17, in
    10. test_03()
    11. File "D:\python\Day08\代码\02-函数中变量的作用域.py", line 13, in test_03
    12. a += 100
    13. UnboundLocalError: local variable 'a' referenced before assignment

    如果要进行修改,使用globle关键字

    1. 例:
    2. a = 100
    3. def test_03():
    4. # 函数内部可以使用全局变量但是无法修改全局变量,如果要进行修改,使用globle关键字
    5. global a #添加修改全局变量的权限
    6. a += 100
    7. print(a)
    8. test_03()

    函数注释

    函数内部:

    '''

    xxx

    '''

    1. 例:
    2. def sum_01(a,b):
    3. return a+b
    4. sum_01(1,2)

    将鼠标拖到sum_01(1,2)上,它会显示如下图所示,下方会显示这个函数的一些注释

    而我们如果要修改注释

    方法如下:

    1. 在函数内部输入'''(解释器会自动给你在后面补充三个''')
    2. 直接按回车键
    3. 将出现的注释删除,写上你想展示的注释

    例:

    展示

    扩展:

    我们也可以直接按住ctrl键然后将鼠标移到函数上,然后点击,可以转到注释

    例:round()

    例round() 我定义在全局中

    值传递与引用传递

    值传递:在传递参数时,仅仅是把值拷贝一份传递给参数的函数,变量的值不发生变化

    1. 例:
    2. def test01(x, y):
    3. x += 10
    4. y += 20
    5. print(x, y)
    6. a = 10
    7. b = 20
    8. test01(a, b) #只是拷贝
    9. print(a) #原变量的值不发生变化
    10. print(b)
    11. 结果:
    12. 20 40
    13. 10
    14. 20

    引用传递:在传递参数的时候,传地址,函数形参获取的值,也是同一块内存

    1. 例:
    2. def test02(nums):
    3. print(id(nums)) #id()用来查看地址,后面会讲
    4. nums.append(10)
    5. nums.append(100)
    6. print(nums)
    7. list1 = [1, 2, 3]
    8. print(id(nums))
    9. test02(list1) #传地址,函数形参获取的值,也是同一块内存
    10. print(list1)
    11. 结果:
    12. 2273748378816
    13. 2273748378816 #可以看出不是拷贝,是同一个地址
    14. [1, 2, 3, 10, 100]
    15. [1, 2, 3, 10, 100]

    匿名函数

    匿名函数:python中将函数作为参数传到另外一个函数里边去

    python中函数参数的数据类型:只要是对象就可以

    python :函数本身就是一个对象

    1. 例:
    2. def compute(a,b):
    3. return a+b
    4. def test01(fn):
    5. a = fn(1,2)
    6. print(a)
    7. test01(compute) #注意:不能写成test01(compute())
    8. #compute()是函数调用,不是对象了,返回的要么是return值,要么是None
    9. 结果:
    10. 3

    lambda匿名函数

    匿名函数:临时使用一次

    python中,存在函数作为参数传递给函数,并且不想被外界访问,而且参数函数足够简单,即可以定义为匿名函数(lambda 表达式)

    格式:
    lambda 传入参数 :函数体 (函数体只能写一行,不能写多行)

    lambda [a,b] : 代码块  ([ ]包起来代表可有可无,可能无传入参数)

    例:

    1. 例:
    2. 与上面效果相同
    3. def test01(fn):
    4. a = fn(1,2)
    5. print(a)
    6. test01(lambda a, b: a + b)
    7. 结果:
    8. 3

    偏函数:

    Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。要注意,这里的偏函数和数学意义上的偏函数不一样。

    在介绍函数参数的时候,我们讲到,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。举例如下:
    int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

    1. >>> int('12345')
    2. 12345

    但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

    1. >>> int('12345', base=8) #注意前面需要加''
    2. 5349 #将8进制‘12345’转换为10进制
    3. >>> int('12345', 16)
    4. 74565 #将16进制‘12345’转换为10进制

    假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

    1. def int2(x, base=2): #缺点是base=2可以改,不固定
    2. return int(x, base)

    这样,我们转换二进制就非常方便了:

    1. >>> int2('1000000')
    2. 64
    3. >>> int2('1010101')
    4. 85

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

    1. >>> import functools #导入模块(后面会讲)
    2. >>> int2 = functools.partial(int, base=2)
    3. >>> int2('1000000')
    4. 64
    5. >>> int2('1010101')
    6. 85

    所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

    注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

    1. >>> int2('1000000', base=10)
    2. 1000000

    最后,创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,当传入:

    int2 = functools.partial(int, base=2)

    实际上固定了int()函数的关键字参数base,也就是:

    int2('10010')

    相当于:

    1. kw = { 'base': 2 }
    2. int('10010', **kw)

    当传入:

    max2 = functools.partial(max, 10)

    实际上会把10作为*args的一部分自动加到左边,也就是:

    max2(5, 6, 7)

    相当于:

    1. args = (10, 5, 6, 7)
    2. max(*args) #求最大值
    3. 结果:
    4. 10

    小结:

    当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

    python3.8新特性


    声明函数参数类型

    在C/C++/JAVA时我们函数传参的时候都是有严格限制参数类型,而我们python则没有

    1. 例:
    2. python:
    3. def fun(a,b,c):
    4. Java:
    5. public static void fn(int a,double b,String c){
    6. }

    但是python3.8之后添加了一个限制方法(注:这个限制是非强制的,只是会提醒你)

    1. def add(x: int, y: float): #用来限制传入的参数类型
    2. print(x + y)
    3. add(1, 1)
    4. add("1","1") #你鼠标放上去会提醒你,但依旧可以执行
    5. 结果:
    6. 2
    7. 11
    8. def add(x: int, y: float) -> float: #->指向限制返回值的类型
    9. print(x + y)
    10. return x + y
    11. add(1, 1)
    12. add("1","1")

    函数的嵌套

    1. def fun1():
    2. b = 20
    3. def fun2():
    4. pass
    5. 函数的嵌套,此时的fun2是局部变量.想像成:
    6. #fun2 = def():
    7. 注意:局部的东西,一般都是局部自己访问使用的

    局部变量,就想在外边使用:return

    想在外边访问fun2,可以将fun2像变量一样进行返回
    return fun2

    1. def fun1():
    2. b = 20
    3. def fun2():
    4. pass
    5. return fun2 #此时我们把函数当做变量进行返回的
    6. b1 = fun1() #此时的b1事实上就是函数fun2()
    7. b1()

    函数作为返回值:

    1. 例:
    2. def lazy_sum(*args):
    3. def sum():
    4. ax = 0
    5. for n in args:
    6. ax = ax + n
    7. return ax
    8. return sum
    9. a = lazy_sum(1)
    10. print(a)
    11. a = lazy_sum(1)
    12. print(a)
    13. 结果:
    14. locals>.sum at 0x000002130129A8C0>#返回一个fun2的函数
    15. locals>.sum at 0x000002130129B910>

    调用一次lazy_sum,返回一个新的函数,即使是相同的参数,两次调用生成的函数也不一样

    并且返回的函数可以再调用,即调用内层函数

    1. def fun1():
    2. b = 20
    3. def fun2(): #fun2 = def(){}
    4. print(b)
    5. print("222222222")
    6. return fun2 #注意:返回函数不要带小括号,有括号是调用
    7. a = fun1() #返回fun2的函数
    8. a() #调用fun2函数
    9. 结果:
    10. 20
    11. 222222222

    函数作为参数进行传递

    此时的实参可以是函数
    代理模式:函数test_func代理了compute

    综上:

    1. 函数可以作为返回值进行返回
    2. 函数可以当做参数进行传递
    3. 函数名本质上就是变量名,指向函数所在的内存地址

    闭包

    闭包:一个函数嵌套另一个函数,内层函数用到外层函数的局部变量,内层函数即为闭包

    1. def outer():
    2. a = 10
    3. def inner():
    4. print(a)
    5. return inner
    6. #内层函数inner即为闭包
    7. a = outer()
    8. a()
    9. 结果:
    10. 10

    如果内层变量想要更改外部变量的值(直接修改)

    1. 例:
    2. def outer():
    3. a = 10
    4. def inner():
    5. a += 1 #报错
    6. print(a)
    7. return inner
    8. a = outer()
    9. a()
    10. 结果:
    11. Traceback (most recent call last):
    12. File "D:\python\Day08\代码\09-闭包.py", line 17, in
    13. a()
    14. File "D:\python\Day08\代码\09-闭包.py", line 11, in inner
    15. a += 1
    16. UnboundLocalError: local variable 'a' referenced before assignment

    我们需要用到关键字nonlocla

    nonlocla:内层变量想要更改外部变量的值,
    在内层函数添加x的声明:
    nonlocal x

    语法结构和规则:

    1. def func():
    2. a = 10
    3. def inner():
    4. nonlocal a
    5. print("原", a)
    6. a += 1
    7. print(a)
    8. return inner
    9. ret = func()
    10. ret() #a = 11
    11. ret() #a = 12
    12. #事实上实现了在全局作用域(外层)对局部变量进行更改
    13. #局部变量的好处:外界很难更改
    14. #不通过inner去更改a:改不了
    15. 结果:
    16. 10
    17. 11
    18. 11
    19. 12

    闭包:

    1. 可以让一个变量常驻在内存当中
    2. 可以避免全局变量被修改

    本质:内层函数对外层函数的局部变量的使用,内层函数被称为闭包

  • 相关阅读:
    从 0 到 1,看我玩弄千万日志于股掌
    Cy3 PEG N-羟基琥珀酰亚胺,花菁染料CY3标记N-羟基琥珀酰亚胺,CY3-N-Hydroxy succinimide
    vr火灾逃生安全科普软件开展消防突击教育安全有效
    BCC源码内容概览(3)
    KV STUDIO的安装与实践(一)
    C++中struct与class区别,C与C++中struct区别
    关于Office阻止访问嵌入对象的解决办法
    C/C++教程 从入门到精通《第十七章》—— MFC开发多人聊天室
    网站文章生成技术-网站文章生成工具免费
    Linux 进程线程
  • 原文地址:https://blog.csdn.net/Starry__Sky222/article/details/133829209