美文网首页
Python-函数

Python-函数

作者: 徐弱西 | 来源:发表于2019-07-14 15:53 被阅读0次

    如何定义函数

    '''
    1、功能的单一化
    2、函数内部需要外部的资源:通过函数的参数来实现
    3、函数执行后的结果需要告诉外界:通过返回值告诉给外界
    '''
    

    函数的参数

    形参与实参

    '''
    形参:在函数定义时()里出现的参数
        -- 形参本身没有实际值(意义),在函数调用时,传入什么实参,形参就装有什么值
    实参:在函数调用时()里出现的参数
        -- 实参有实际值(意义)
        
    重点:函数调用传参:将实参的值赋值给形参 | 形参要获取外界的值只能通过实参进行获取
    '''
    def fn(a, b):  # a, b:形参
        pass
    a = 10
    fn(a, 20)  # a, 20:实参
    
    code:
    # 形参与实参
    def fn(a, b=10, *args, c, d=20, e, **kwargs):
        pass
    
    a = 100
    b = '200'
    
    def fn1(a, b):  # 形参:在函数定义时()里出现的参数
        print(a, b)
    
    fn1(a, '2000')  # 实参:在函数调用时()里出现的参数
    # 函数调用传参:将实参的值赋值给形参
    # 实参有实际值(意义)
    # 形参本身没有实际值(意义),在函数调用时,传入什么实参,形参就装有什么值
    
    print('end')
    
    

    两种实参

    '''
    位置实参:
    1.传参两种方式:实参名 | 实参具体值
    2.必须按位置对形参进行传值
    
    
    关键字实参:
    1.传参两种方式:形参名=实参名 | 形参名=实参值
    2.可以指名道姓对形参进行传值,所以可以不用按位置进行传参
    '''
    
    def func(a, b, c):
        print(a, b, c)
    
    # func(10, b=20, 200)  报错:SyntaxError: positional argument follows keyword argument
    # 重点:两种实参在一起进行传参时:必须位置在前,关键字在后
    
    code:
    实参
    def fn(a, b):
        print(a, b)
    
    # 实参:
    # 1.位置实参: 按位置先后进行传参,a,b不能被颠倒位置进行传参,a永远比b先接受值
    fn(10, 20)
    fn(20, 10)
    a = 100
    b = 200
    fn(a, b)
    fn(b, a)
    # 传参两种方式:实参名 | 实参具体值
    
    # 2.关键字实参:指名道姓进行传参,a,b能被颠倒位置进行传参,名字指向谁,就是谁接受值
    c = 1000
    fn(a=10, b=c)
    fn(b=20, a=10)
    # 传参两种方式:形参名=实参名 | 形参名=实参值
    
    
    # 结合传参
    def func(a, b, c):
        print(a, b, c)
    
    # func(10, b=20, 200)  报错:SyntaxError: positional argument follows keyword argument
    # 两种实参在一起进行传参时:必须位置在前,关键字在后
    
    
    形参
    '''
    形参种类:
    1)位置形参
        -- 普通位置形参
        -- 默认值形参
        -- 可变长位置形参
    
    2)关键字形参
        -- 有默认值关键字形参
        -- 无默认值关键字形参
        -- 可变长关键字形参
    '''
    
    
    def fn1(a, b, *, x, y):
        pass
    
    
    # fn1()
    # 位置形参与关键字形参的分水岭 *
    
    # 重点:
    # 位置实参只能给位置形参进行传值
    # fn1(10, 20, 30, 40)  # 只有两个位置,给了四个位置
    # 关键字实参可以给位置形参与关键字形参进行传值
    # fn1(x=30, y=40, a=10, b=20)
    
    
    
    # part2
    # 两个带默认值的形参
    def fn2(a=10, *, x=20):
        print(a, x)
    fn2(100, x=200)
    # 总结:
    # 1.有默认值的参数可以不用传值
    # 2.*前有默认值的叫默认值参数,属于位置形参,可以被位置及关键字实参进行传值
    # 3.*后有默认值的叫有默认值的关键字形参,属于关键字形参,只能被关键字实参进行传值
    
    # def get_p(name, sex='男'):
    #     pass
    # get_p('Bob', '女')
    
    
    # part3
    def fn3(a, b=10, *, x, y=20, z):
        print(a, b, x, y, z)
    fn3(100, x=200, z=300)
    # 总结:
    # 1.没有默认值的必须传参,有默认值的可以传也可以不传
    # 2.位置有值的必须出现在无值之后,关键字顺序不做要求
    
    # part4
    def fn4(a, b=10, *args, x, **kwargs):
        print(a, b, x)
        print(args)
        print(kwargs)
    fn4(10, 20, 30, x=100, y=200, z=300)
    # 总结:
    # 1.可变长是用来接收未接收完的值(接收0到n个):
    #   -- *args用来接收所以没有接收完的位置(只能接收位置实参)
    #   -- **kwargs用来接收所以没有接收完的关键字(只能接收关键字实参)
    # 2.*args必须出现在所以位置参数之后,**kwargs必须出现在所以参数之后
    
    # 假设第一个位置永远是参数name
    def func4(*args, **kwargs):
        name = args[0]  # 将name抽出来
    
    def func44(name, *args, **kwargs):
        # name 可以直接接收,省了抽出来的过程
        pass
    
    
    
    # part5
    def fn5(*args, **kwargs):
        print(args, kwargs)  # args=(10, 20)  kwargs={'x': 100, 'y': 200}
    
    def fn55(*args, **kwargs):
        print(args, kwargs)  # args=(10, 20)  kwargs={'x': 100, 'y': 200}
        fn5(*args, **kwargs)  # *args就会把元组打散传递,**kwargs就会把字典打散传递
    
    fn55(10, 20, x=100, y=200)
    
    # 容器类型可以打散传值
    def temp(*args, **kwargs):
        print(args, kwargs)
    ls = [1, 2, 3, 4, 5]
    dic = {'a': 1, 'b': 2}
    temp(*ls, **dic)
    
    

    两大形参分类

    '''
    形参种类:
    1)位置形参
        -- 普通位置形参
        -- 默认值形参
        -- 可变长位置形参
    
    2)关键字形参
        -- 有默认值关键字形参
        -- 无默认值关键字形参
        -- 可变长关键字形参
    '''
    def fn(a, b, *, x, y):  # 位置形参:a, b  关键字形参: x, y
        pass
    
    '''
    重点:
    1.*为分水岭
    2.位置实参只能给位置形参进行传值
    3.关键字实参可以给位置形参与关键字形参进行传值
    '''
    

    两个带默认值的形参

    def fn2(a=10, *, x=20):
        print(a, x)
    fn2(100, x=200)
    # 总结:
    # 1.有默认值的参数可以不用传值
    # 2.*前有默认值的叫默认值参数,属于位置形参,可以被位置及关键字实参进行传值
    # 3.*后有默认值的叫有默认值的关键字形参,属于关键字形参,只能被关键字实参进行传值
    # 4.如果省略*, 有默认值的形参都是默认值参数
    
    

    不带默认值与带默认值形参结合使用

    def fn3(a, b=10, *, x, y=20, z):
        print(a, b, x, y, z)
    fn3(100, x=200, z=300)
    # 总结:
    # 1.没有默认值的必须传参,有默认值的可以传也可以不传
    # 2.位置有值的必须出现在无值之后,关键字顺序不做要求
    

    可变长位置形参与可变长关键字形参

    def fn4(a, b=10, *args, x, **kwargs):
        print(a, b, x)
        print(args)
        print(kwargs)
    fn4(10, 20, 30, x=100, y=200, z=300)
    # 总结:
    # 1.可变长是用来接收未接收完的值(接收0到n个):
    #   -- *args用来接收所有没有接收完的位置(只能接收位置实参)
    #   -- **kwargs用来接收所有没有接收完的关键字(只能接收关键字实参)
    # 2.*args必须出现在所以位置参数之后,**kwargs必须出现在所以参数之后
    
    
    # 常见应用场景
    # 假设第一个位置永远是参数name
    def func4(*args, **kwargs):
        name = args[0]  # 将name抽出来
    
    def func44(name, *args, **kwargs):
        # name 可以直接接收,省了抽出来的过程
        pass
    

    总结

    '''
    1.位置实参只能给位置形参传值
    2.关键字实参可以给位置及关键字形参传值
    3.有默认值的可以不用传参
    4.可变长位置形参只能接受位置实参,接受位置形参没有接收完的位置实参,存放到元组中
    5.可变长关键字形参只能接受关键字实参,接受关键字形参没有接收完的关键字实参,存放到字典中
    6.*args必须出现在所有位置形参之后,**kwargs必须在所有形参之后
    '''
    

    可变长整体传参:打散传值

    def fn(*args, **kwargs):
        print(args, kwargs)
        
    fn([1, 2, 3], {'a':1 , 'b': 2})  # =>接收到的 ([1, 2, 3], {'a':1 , 'b': 2})  {}
    fn(*[1, 2, 3], **{'a':1 , 'b': 2})  # =>接收到的 (1, 2, 3)  {'a':1 , 'b': 2}
    
    # 注:字符串也可以作为单列集合进行打散传递
    fn(*'abc')  # => ('a', 'b', 'c')  {}
    

    函数对象

    # 函数名就是存放了函数的内存地址,存放了内存地址的变量都是对象,即 函数名 就是 函数对象
    
    # 函数对象的应用场景
    # 1 可以直接被引用
    # 2 可以当作函数参数传递
    # 3 可以作为函数的返回值
    # 4 可以作为容器类型的元素
    
    # 功能体
    def add(n1, n2):
        return n1 + n2
    
    def low(n1, n2):
        return n1 - n2
    
    def jump(n1, n2):
        return n1 * n2
    
    # 完成功能
    def computed(n1, n2, fn):  # fn = add|low|jump
        res = fn(n1, n2)  # 调用具体的功能
        return res
    
    # 功能对应关系
    method_map = {  # 指令与函数对象的对应关系
        '1': add,
        '2': low,
        '3': jump
    }
    
    # 获取功能
    def get_method(cmd):
        if cmd in method_map:
            return method_map[cmd]  # 返回 add|low|jump
        return add  # 当指令错误,add作为默认功能
    
    while True:
        cmd = input('cmd: ')
        res = get_method(cmd)(10, 20)  # 根据指令获取功能并调用得到结果
        print(res)
    
    code:
    # part1
    owen_a = 10
    # owen_a存放10的地址,所以也是对象,普通的整型对象
    
    # 函数对象:存放函数地址的变量就叫函数对象,就是函数名
    def fn():
        print(1)
        print(2)
        print(3)
        return 1
    print(fn)
    # 1.函数对象():拿到函数地址并执行 - 函数的调用
    # 2.函数调用一定会得到一个结果 - 函数的返回值 - 函数值: res=fn() == 函数调用后res=1
    res = fn()
    print(res)
    res = 1
    print(res)
    
    print('------------------------')
    # part2
    # 应用场景:
    # 1 可以直接被引用
    # 2 可以当作函数参数传递
    # 3 可以作为函数的返回值
    # 4 可以作为容器类型的元素
    def fn2():
        print('fn2 run')
    # fn2()
    aaa = fn2  # 直接赋值
    # aaa()
    
    def fn22(fn):  # fn = aaa = fn2  # 作为参数
        fn()
    fn22(aaa)
    
    def fn222():
        # return fn2()
        return fn2  # 作为返回值
    res = fn222()  # res = fn2() = None  |  res = fn2 = 函数对象
    print(res())
    
    ls = [fn2, 10, 20]  # 作为容器对象的成员
    print(ls[1])
    print(ls[0]())
    
    
    
    # 案例:
    
    def add(n1, n2):
        return n1 + n2
    
    def low(n1, n2):
        return n1 - n2
    
    def jump(n1, n2):
        return n1 * n2
    
    def computed(n1, n2, fn):
        res = fn(n1, n2)
        return res
    
    method_map = {
        '1': add,
        '2': low,
        '3': jump
    }
    
    def get_method(cmd):
        if cmd in method_map:
            return method_map[cmd]
        return add
    
    while True:
        cmd = input('cmd: ')
        res = 0
        # if cmd in method_map:
        #     # res = method_map[cmd](10, 20)
        #     fn = get_method(cmd)
        #     res = fn(10, 20)
        res = get_method(cmd)(10, 20)
        print(res)
    
    
    # while True:
    #     cmd = input('cmd: ')
    #     res = 0
    #     if cmd == '1':
    #         res = computed(10, 20, add)
    #     elif cmd == '2':
    #         res = computed(10, 20, low)
    #     elif cmd == '3':
    #         res = computed(10, 20, jump)
    #     print(res)
    
    

    函数的嵌套调用

    # 函数的嵌套调用:在一个函数内部调用另一个函数
    # 求两个数最大值
    def max_two(n1, n2):
        if n1 > n2:
            return n1
        return n2
    
    # 求三个数最大值
    def max_three(n1, n2, n3):
        max = max_two(n1, n2)
        return max_two(max, n3)
    
    # 求四个数最大值
    def max_four(n1, n2, n3, n4):
        max = max_three(n1, n2, n3)
        return max_two(max, n4)
    print(max_four(20, 50, 30, 50))
    
    code:
    # 函数的嵌套调用:在一个函数内部调用另一个函数
    def fn1():
        pass
    def fn2():
        fn1()  # 函数的嵌套调用
    def fn3():
        fn2()  # 函数的嵌套调用
    fn3()
    
    # 案例:
    # 求两个数最大值
    def max_two(n1, n2):
        if n1 > n2:
            return n1
        return n2
    
    # 求三个数最大值
    def max_three(n1, n2, n3):
        max = max_two(n1, n2)
        return max_two(max, n3)
    
    # 求四个数最大值
    def max_four(n1, n2, n3, n4):
        max = max_three(n1, n2, n3)
        return max_two(max, n4)
    print(max_four(20, 50, 30, 50))
    

    名称空间

    # 名称空间:存放名字与内存空间地址对应关系的容器
    # 作用:解决由于名字有限,导致名字重复发送冲突的问题 - 内置全局局部可以同时使用一个名字存放不同地址
    
    # 三种名称空间
    # Built-in:内置名称空间;系统级,一个;随解释器执行而产生,解释器停止而销毁
    # Global:全局名称空间;文件级,多个;随所属文件加载而产生,文件运行完毕而销毁
    # Local:局部名称空间;函数级,多个;随所属函数执行而产生,函数执行完毕而销毁
    
    # 加载顺序:Built-in > Global > Local
    #   -- 采用堆栈存储数据的方式(压栈),导致内置最后被访问
    
    code:
    # part1
    '''
    x = 100
    def fn():
        a = 10
    fn()
    
    # 没有缩进直接使用, 和在其他函数中,都只能使用x,不能使用函数内部的a
    def func():
        print(x)
    func()
    
    # 问题点:什么导致变量的访问权限
    '''
    
    # part2
    # 名称空间:存放变量名与栈区内存地址的对应关系
    print(len('123'))
    len = 10
    print(len)
    del len
    print(len('abc'))
    print(len)
    len = 200
    print(type(len))
    
    def fn():
        len = 2000
        print(len)
    fn()
    print(len)
    

    函数的嵌套定义

    # 函数的嵌套定义:在函数内部定义函数
    # 诞生的理由:一个函数想使用另一个函数内部的变量,可以定义在其内部
    def func():
        a = 10
        def fn():
            print(a)
        return fn
    
    new_fn = func()
    new_fn()
    
    code:
    '''
    # 函数的嵌套定义:在函数内部定义函数
    # 诞生的理由:一个函数想使用另一个函数内部的变量,可以定义在其内部
    def func():
        a = 10
        def fn():
            print(a)
        return fn
    
    new_fn = func()
    new_fn()
    '''
    
    '''
    # global关键字: 统一局部与全局的变量名
    
    a = 100
    def fn1():
        global a
        a = 200  # 让函数的局部变量a与全局变量a统一,两者是一个
    print(a)
    fn1()
    print(a)
    '''
    
    # nonlocal关键字:统一局部与嵌套局部的变量名
    def fn2():
        num = 666
        def fn22():
            nonlocal num
            num = 888
        fn22()
        print(num)
    fn2()
    
    
    # 作用域:
    
    len = 10
    def fn3():
        len = 100
        def fn33():
            len = 1000
            print('1:', len)
        fn33()
        print('2:', len)
    fn3()
    print('3:', len)
    

    两个与函数有关的关键字:global nonlocal

    # global:统一局部与全局的变量名
    num = 10
    def outer():
        # global num
        # num = 100
        def inner():
            global num
            num = 1000
            
    # nonlcal: 统一局部与嵌套局部的变量名
    def outer():
        num = 100
        def inner():
            nonlocal num
            num = 1000
    

    作用域

    # 作用域:名字起作用的范围
    # 作用:解决同名字可以共存问题 - 不同作用域相同名字的值都能在其作用域范围下进行使用
    '''
    四种作用域: LEGB
    Built-in:内置作用域 - 所有文件所有地方都可以被访问
    Global:全局作用域 - 在当前文件的所有位置
    Enclosing:嵌套作用域 - 自身内部与内部的子函数
    Local:局部作用域 - 只有自身内部
    '''
    # 加载顺序:Built-in > Global > Enclosing > Local
    # 访问(查找)顺序:报错 < Built-in < Global < Enclosing < Local
    # 作用范围:Built-in > Global > Enclosing > Local
    

    相关文章

      网友评论

          本文标题:Python-函数

          本文链接:https://www.haomeiwen.com/subject/qdtikctx.html