zoukankan      html  css  js  c++  java
  • 函数/匿名函数

    函数的定义

    def func():
        print(1)
        print(2)
        print(3)
        return
        print(4)
    func()
    
    结果:
    1
    2
    3
    4
    View Code

    定义:def 关键字开头,空格之后接函数名和圆括号(),最后为冒号:,def 是固定的不能改变,空格将def关键字和函数名分开,函数名的命名规则和变量一样

    调用:就是 函数名()

    rerutn : 当函数遇到return是,函数结束执行

    函数的执行流程

    函数只有在调用时才会执行,由上到下逐行执行

    函数的返回值

    return 关键字 ,谁调用就返回给谁

    def func():
        s = 1+2
        print(s)
    sum1 = func()
    print(sum1)
    View Code

     不写retnrn时,会默认返回一个None

    def func():
        s = 1+2
        print(s)
    sum1 = func()
    print(sum1)
    
    结果:
    3
    None
    View Code

    只写return,后面不写其他内容,也会返回None

    def func():
        s = 1+2
        print(s)
        return
    sum1 = func()
    print(sum1)
    
    结果:
    3
    None 
    View Code

    写return和不写return的区别,当函数中遇到return时,此函数结束,不会在继续执行

    def func():
        s = 1+2
        return
        print(s)   #print(s)并没有执行
    sum1 = func()
    print(sum1)
    
    结果:
    None
    View Code

    返回一个值,返回的是值,而不是某个变量,返回的数据类型是其本身的数据类型

    def func():
        s = 1+2
        return s,1,2,['a','b']
    sum1 = func()
    print(sum1)
     结果: 3
    View Code

    返回多个值

    def func():
        s = 1+2
        return s,1,2,['a','b']
    sum1 = func()
    print(sum1)
    
    结果:
    (3, 1, 2, ['a', 'b'])  
    View Code

    返回的多个值会被组织成一个元组被返回,也可以用多个值来接受

    def func():
        return 1,2,['q','w'],3
    a,b,c,d = func()
    print(a,b,c,d)
    结果:
    1 2 ['q', 'w'] 3
    View Code

    注意:return和返回值之间要有空格,可以返回任意数据类型的值

     函数的参数

     参数:也就是函数括号里的内容  函数在调用的时候指定一个具体的变量的值 就是参数

    def func(n):    #形参
        print("hello"+n)
    func("world")  #实参    #将wolrd传入到n的过程叫传参
    View Code

    传入多个参数,参数之间用逗号分隔

    def func(x,y):
        max1 = x if x > y else y
        return max1
    n = func(3,4)
    print(n)
    View Code

    位置参数

    按照位置传值,实参的角度

    def func(x,y):
        # 此时 x=3 y=4
        max1 = x if x > y else y
        return max1
    n = func(3,4)
    print(n)
    View Code

    按照关键字传值

    def func(x,y):
        # 此时 x=4 y=3
        max1 = x if x > y else y
        return max1
    n = func(y=3,x=4)
    print(n)
    View Code

    混合传参

    def func(x,y):
        # 此时 x=4 y=3
        max1 = x if x > y else y
        return max1
    n = func(4,y=3)
    print(n)
    View Code

    注意:位置参数必须在关键字参数前面,对于一个形参只能赋值一次

    默认参数

    将变化比较小的值设置为默认参数

    默认参数

    def func(name,state = "CN"):
        print(name,state)
    func('wanglan')
    View Code

    想要修改默认参数,传值即可

    def func(name,state = "CN"):
        print(name,state)
    func('wanglan','USA')
    View Code

    默认参数陷阱

    def func(a,l=[]): # 当函数执行时,发现有默认参数,会在内存中生成一个列表,l=[]只会创建一次,并不会多次创建,在函数内部使用时相当于全局变量,只是其它函数无法使用
        l.append(a)
        print(l)
    func(1) #当函数调用时,会在列表中添加1
    func(2) #第二次调用,会继续添加
    func(3) #第三次调用,继续添加
    
    结果:
    [1]
    [1, 2]
    [1, 2, 3]
    View Code
    def func(a,l=[]): #只要是默认参数是一个可变数据类型,通过默认参数对其修改,修改的就是同一个
        l.append(a)
        print(l)
    func(1) #使用默认参数修改
    func(2,[]) #不在使用默认参数,传入一个空列表
    func(3)  #使用默认参数修改
    
    结果:
    [1]
    [2]
    [1, 3]
    View Code

    动态位置参数

     按位置传值多余的参数由args统一接受,保存成一个元组的形式

    def func(*args):
        print(args)
    func('Hello','world','wang','lan')
    
    结果:
    ('Hello', 'world', 'wang', 'lan')  #收到的结果是一个元组
    View Code

    注意:动态参数要写在位置参数后面

     动态默认参数

     按默认传值多余的参数由kwargs统一接受,保存成一个字典的形式

    def func(**kwargs):
        print(kwargs)
    func(a = 'Hello',b = 'world',c = 'wang',d = 'lan')
    
    结果:
    {'a': 'Hello', 'b': 'world', 'c': 'wang', 'd': 'lan'}  #收到的结果是一个字典
    View Code

    最终顺序: 位置参数 > *args(动态位置参数)  > 默认值参数 > **kwargs(动态默认参数)

     其他传参方式

     接受所有的参数

    def func(*args,**kwargs):
        print(args,kwargs)
     func(1,23,5,a=1,b=6)
    View Code

    动态参数其他传参

    st = [1,4,7]
    # 方法一
    def func(*args):
        print(args)
     func(lst[0],lst[1],lst[2])
     
    # 方法二
    def func(*args):# 在形参的位置上用*把收到的参数组合成一个元祖
        print(args) 
    func(*lst)  #在实参的位置上用*将lst(可迭代对象)按照顺序打散
    View Code

    字典也可以进行打散,不过需要**

    def func(**kwargs):
        print(kwargs)  #返回字典
    func(**dic)
    
    
    def func(**kwargs):
        print(*kwargs) #加上*返回的就是字典的key
    func(**dic)
    View Code

    命名空间和作用域

     在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了,  至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空

    def fun():   
        a = 10
        print(a)
    fun()
    print(a)    # a不不存在了了已经
    
    结果:
    NameError: name 'a' is not defined
    View Code

    命名空间:
        内置命名空间 :作用域 全局和局部,加载是在运行之后,代码之前
        全局命名空间 :作用域 全局和局部,加载是在运行代码的时候
        局部命名空间 :作用域 在局部,加载是在调用的时候

    加载顺序:

        内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载

    取值 :

        在局部调用:局部命名空间->全局命名空间->内置命名空间 

    x = 1
    def func():
        x = 2      #局部存在使用局部
        print(x)
    func()
    
    结果
    2
    
    x = 1
    def func():
        x = 2
        def func1():  #不存在调用父级,找到就使用,找不到就使用全局
            print(x)   
        func1()
    func()
    
    结果
    2
    View Code

    覆盖 :
        同一个名字 : 局部覆盖全局和内置,全局覆盖内置
        永远不要起和你知道的内置命名空间中重名的名字 

    可以通过globals()函数来查看全局作用域中的内容,  也可以通过locals()来查看局部作用域中的变量量和函数信息

    def func():
        a = 40
        b = 20
        print("哈哈")
        print(a, b)     # 这里使用的是局部作用域
        print(globals())    # 打印全局作用域中的内容
        print(locals())     # 打印局部作用域中的内容
    func()
    View Code

    函数的嵌套

    def f1():
        def f2():
            def f3():
                print("in f3")
            print("in f2")
            f3()
        print("in f1")
        f2()
    f1()
    View Code
    def max2(x,y):
        m  = x if x>y else y
        return m
    def max4(a,b):
        res1 = max2(a,b) #调用max2函数
        return res1
    n = max4(6,2)
    print(n)
    View Code

    global和nonlocal

    global:在局部改全局

    a = 10
    def func():   
        global a    # 加了个global表示将局部变量改为全局变量
        a = 20   
    print(a)
    func()
    print(a)
    View Code

    nonlocal:在小局部改大局部,两个局部之间一定有嵌套关系(修改父级变量),如果父级没有继续向上找,直到函数的第一层,如果还没有就保错,nonlocal不能修改全局变量

    def f1():
        a = 1
        def f2():
            nonlocal a  #更改父级变量
            a = 2   #将父级变量的a=1 修改为a =2 
        f2()
        print('a in f1 : ',a)
    
    f1()
    View Code

    函数名的本质

    1. 函数名可以被引用

    def func():
        print('in func')
    f = func
    print(f)
    View Code

    2函数名可以被当作容器类型的元素

    def f1():
        print('f1')
    
    
    def f2():
        print('f2')
    
    
    def f3():
        print('f3')
    
    l = [f1,f2,f3]
    d = {'f1':f1,'f2':f2,'f3':f3}
    
    #调用
    l[0]()
    d['f2']()
    View Code

    3.函数名可以当作函数的参数和返回值,就是可以当普通变量用

    def login_failed():
        print('登陆失败')
    
    def index():
        print('欢迎来到首页')
    
    def login(usr,pwd):
        if usr == 'wanglan' and pwd == '123':
            return index
        else:
            return login_failed
    res_func = login('wanglan','123')
    res_func()
    View Code

    4.函数名可以作为函数的参数

    def login():
        print('欢迎登陆')
    
    def index(auth):
        auth()
        print('欢迎来到首页')
    
    index(login)
    View Code

    闭包

    内部函数使用了外部函数的变量,内部函数就是一个闭包

    def func():
        name = 'wanglan'
        def inner():
            print(name)

    闭包常用的用法

    def func():
        name = 'wanglan'
        def inner():
            print(name)
        return inner
    f = func()
    f()
    View Code

    可以通过__closure__ 来查看是不是闭包,有值就是,没值就不是

    def func():
        name = 'wanglan'
        def inner():
            print(name)
        print(inner.__closure__)
        return inner
    f = func()
    f()
    View Code

    闭包嵌套

    def wrapper():    #1加载
        money = 1000
        def func():    #3.加载
            name = 'wanglan'
            def inner():  #6.加载
                print(name,money) #9.打印
            return inner  #7.返回内存地址
        return func   #4.返回内存地址
    f = wrapper()  #2.调用
    i = f() #5.调用
    i() #8.调用
    View Code

    匿名函数

    匿名函数:为了解决那些功能很简单的需求而设计的一句话函数

     def calc(n):
        return n ** n
    print(calc(10))
    
    # 换成匿名函数
    calc = lambda n: n ** n   #lambda:关键字   n:形参   n ** n :返回值,就是return后面的内容
    print(calc(10))
    View Code

    小结

    函数的定义规则

    1.定义:def 关键词开头,空格之后接函数名称和圆括号()。
    2.参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号分割。
        参数可以定义多个,也可以不定义。
        参数有很多种,如果涉及到多种参数的定义,应始终遵循位置参数、*args、默认参数、**kwargs顺序定义。
        如上述定义过程中某参数类型缺省,其他参数依旧遵循上述排序
    3.注释:函数的第一行语句应该添加注释。
    4.函数体:函数内容以冒号起始,并且缩进。
    5.返回值:return [表达式] 结束函数。不带表达式的return相当于返回 None
    
    def 函数名(参数1,参数2,*args,默认参数,**kwargs):
            """注释:函数功能和参数说明"""
            函数体
            ……
            return 返回值
    View Code

    函数的调用规则

    1.函数名()
        函数名后面+圆括号就是函数的调用。
    2.参数:
        圆括号用来接收参数。
        若传入多个参数:
            应按先位置传值,再按关键字传值
            具体的传入顺序应按照函数定义的参数情况而定
    3.返回值
        如果函数有返回值,还应该定义“变量”接收返回值
        如果返回值有多个,也可以用多个变量来接收,变量数应和返回值数目一致
    
    无返回值的情况:
    函数名()
    
    有返回值的情况:
    变量 = 函数名()
    
    多个变量接收多返回值:
    变量1,变量2,... = 函数名()
    View Code

    命名空间

    一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
    小范围的可以用大范围的
    但是大范围的不能用小范围的
    范围从大到小(图)

    在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
    如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
    如果都没有,报错

    函数的嵌套:

      嵌套调用

      嵌套定义:定义在内部的函数无法直接在全局被调用

    函数名的本质:

      就是一个变量,保存了函数所在的内存地址

    闭包:

      内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数

     

  • 相关阅读:
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
    Data Structure and Algorithm
  • 原文地址:https://www.cnblogs.com/wanglan/p/9902453.html
Copyright © 2011-2022 走看看