zoukankan      html  css  js  c++  java
  • 函数基础语法及使用

    函数

    函数是用来盛放代码的容器,一个函数就是一个功能。

    作用:

    1、减少代码冗余。

    2、增强代码可读性。

    3、使程序易于扩展。

    函数使用

    原则:先定义,后调用。

    函数名定义规则与变量名相同,函数名尽量用动词。

    # 定义函数基本结构
    def 函数名():
        代码体
    
    # 定义函数的完整结构
    def 函数名(参数1,参数2,参数3。。。):
        """
        注释信息
        """
        代码体
        return 返回值
    

    定义阶段:只检查语法,不执行代码。

    和定义变量相同,先申请一块内存空间,将代码放进去,将内存空间与函数名关联。

    # abc虽然没有定义变量,但这是没定义变量引发的逻辑错误,并没有语法错误,所以不会报错。
    def f():
        a + b + c
    

    调用阶段:执行函数体代码。

    调用阶段是先通过函数名找到代码体对应的内存空间,括号()表示执行代码体的代码。

    名字对应的是内存地址,打印函数名得到的是函数体的内存地址。

    def f():
        pass
    print(f)
    <function f at 0x0000000000507160>
    

    函数定义的三种形式

    无参函数

    def f1():
    	代码体
    

    有参函数

    def f2(x,f):
        代码体
    

    空函数

    用于先定义好程序大概所要用的功能,然后再根据思路补全函数。

    def f3():
        pass
    

    函数的提示信息

    Python不会限制传入参数的数据类型,但我们在定义时可以提示调用者函数参数和返回值的数据类型。

    def func(x:'参数1的提示信息',y:'参数2的提示信息')->'返回值得提示信息':
        pass
    
    # 查看提示信息,返回一个字典。
    print(func.__annotations__)
    {'x': '参数1的提示信息', 'y': '参数2的提示信息', 'return': '返回值的提示信息'}
    

    定义时的注释

    def f1(x,y):
        """
        函数功能注释
        :param x: 参数x的注释
        :param y: 参数y的注释
        :return: 返回值得注释
        """
        pass
    
    # 使用help()内置函数查看函数注释信息.
    help(f1)
    
    Help on function f1 in module __main__:
    
    f1(x, y)
        函数功能注释等
        :param x: 参数x的注释
        :param y: 参数y的注释
        :return: 返回值得注释
    

    函数调用的三种形式

    1、语句形式。

    f1()
    

    2、表达式形式。

    ret = f() + 10
    

    3、函数调用可以当做一个参数传给另一个函数。

    f1(f2())
    

    函数的返回值

    return的两种作用

    1、控制返回值。

    情况1:没有return或return后为空。此时返回值为None。

    def f1():
        pass
    print(f1())
    None
    
    def f2():
        return
    print(f2)
    None
    

    情况二:单个返回值。

    def f1():
        return 10
    print(f1())
    10
    

    情况三:用逗号分隔返回多个值。多个值会以元组的形式返回。

    def f1(a,b,c):
        return a,b,c
    
    print(f1(1,2,3))
    (1, 2, 3)
    

    返回值的id和函数调用的id是同一个。

    def f(a):
        return a
    res = f(3)
    print(id(res), id(f(3)))
    8791056713440 8791056713440
    

    2、终止函数

    函数内可以有多个return,函数执行过程中,遇到return就会立即终止函数,并将return后面的值当做本次调用的结果返回。

    def f1(a,b):
        if a >b:
            return a
        else:
            return b
    print(f1(10,20))
    20
    

    函数的参数

    两大类:

    • 形参:在定义函数时,括号内指定的参数,称之为形式参数,简称形参,本质就是变量名。
    • 实参:在函数调用时,括号内传入的值,称之为实际参数,简称实参,本质就是变量值。
    def total(a,b):
        print(a + b)
    total(10,20)
    
    # a,b就是形参。
    # 10,20就是实参。
    

    实参与形参的关系:

    在调用函数时,实参的值会绑定给形参,该绑定关系可以在函数内使用。在函数调用结束后,会解除绑定关系。

    def f1(a,b):
        print(a + b)  # 函数内可以访问到a和b
    f1(1, 2)
    3
    
    # 函数外则无法访问到a和b
    print(a, b)
    NameError: name 'a' is not defined
    

    形参:

    在函数调用时调用一次函数形参只能被传一次值,不能重复传值。

    位置形参:

    在定义函数时,按照从左到右的顺序依次定义的变量名,称之为位置形参。

    特点:必须被传值,多一个不行,少一个不行。

    # 必须传入和位置参数同样数量的值。
    def func(a, b):
        pass
    
    func(10)
    TypeError: func() missing 1 required positional argument: 'b'
    
    # 不能重复传值。
    func(111,222,a=333)
    TypeError: func() got multiple values for argument 'a'
    

    默认形参(具有默认值得形参):

    在定义函数时,就已经为某个形参赋值,该形参就称为默认参数。

    特点:在调用阶段可以不用给默认形参传值。若有传值,新值会覆盖默认值。

    def f(x, y=10):
        print(x, y)
    f(20)
    20 10
    

    注意:默认形参的值是在函数定义阶段规定死,之后的改变不会影响。默认形参的值最好为不可变类。

    n = 10
    print(f'函数定义前 n:    {id(n)}')
    
    def f1(x, y=n):  # 在定义阶段 y所指向的内存地址已经固定。
        print(f'函数内 y:    {id(y)}')
    
    n = 111  # n 的值为不可变类型,在值改变后内存地址也改变,但不会影响函数已定义的值。
    print(f'函数定义后 n:    {id(n)}')
    f1(222)
    
    函数定义前 n:    8790942025664
    函数定义后 n:    8790942028896
    函数内 y:    8790942025664
    222 10
    

    注:默认形参的值若为可变类型,则会被函数定义后的改变所影响。

    n = [10,20]
    print(f'函数定义前 n:    {id(n)}')
    
    def f1(x, y=n):  # 在定义阶段 y所指向的内存地址已经固定。
        print(f'函数内 y:    {id(y)}')
        print(x,y)
    
    n.append(30)  # n 的值为可变类型,在值改变后内存地址不变,还是指向同一个内存地址。
    print(f'函数定义后 n:    {id(n)}')
    f1(222)
    
    函数定义前 n:    41272960
    函数定义后 n:    41272960
    函数内 y:    41272960
    222 [10, 20, 30]
    

    写函数时,函数不应该被定义之后的外界因素影响。

    也就是说,在函数定义完后,函数运行结果应该是可预测的。默认形参的默认值若为可变类型,会让最后的结果充满不确定性,给人带来困惑。

    可变长参数*和**

    *会将溢出位置实参汇总成元组,然后赋值给其后变量名,通常应该是args。

    def f(a,b,*args):
        print(a,b)
        print(args)
    f('哼','哧','哈','嘿')
    哼 哧
    ('哈', '嘿')
    
    # 也可以不给*传值。结果为空元组。
    f('哼','哧')
    哼 哧
    ()
    

    利用*写一个接收能任意个数值的求和函数。

    def total(*args):
        n = 0
        for i in args:
            n += i
        return n
    print(total(1,2,3,4,5))
    15
    

    **会将溢出关键字实参汇总成字典,然后赋值给其后变量名,通常应该是kwargs。

    def f(a,b,**kwargs):
        print(a,b)
        print(kwargs)
    
    f('哼','哧',x='哈',y='嘿')
    
    哼 哧
    {'x': '哈', 'y': '嘿'}
    
    # 同样也可以不给**传值,结果为空字典。
    哼 哧
    {}
    

    *和**的组合使用,能接收符合语法的任意实参。

    def f(*args,**kwargs):
        print(args)
        print(kwargs)
    
    f(1,2,3,4,5,m=6,n=7,x=8,y=9)
    (1, 2, 3, 4, 5)
    {'m': 6, 'n': 7, 'x': 8, 'y': 9}
    

    命名关键字形参

    在*args之后,**kwargs之前的参数,也可以有默认值,仅接受关键字实参。

    def f(a,b,*args,c='嘿',d,**kwargs):
        print(a,b)
        print(args)
        print(c,d)
        print(kwargs)
    
    f(10,20,30,40,d='哈',k1='v1',k2='v2')
    
    10 20
    (30, 40)
    嘿 哈
    {'k1': 'v1', 'k2': 'v2'}
    

    形参最终顺序

    语法规定,违反则报语法错误。

    func(位置形参,默认形参,*args,命名关键字形参,**kwargs)
    

    实参:

    位置实参:

    在调用函数时,按照从左到右的顺序依次传入的值,称之为位置实参。

    特点:按照位置与形参一一对应。

    # 必须传入和位置参数同样数量的值,a和b能收到什么值取决于实参的位置。
    def func(a, b):
        pass
    
    func(10,20)
    func(20,10)
    

    关键字实参:

    在调用函数时,按照key=value的形式指定的实参,称之为关键字实参。

    特点:可以打乱顺序,但仍能为指定的形参传值。

    def func(a, b):
        print(a,b)
    
    func(10,20)
    10 20
    func(b=20,a=10)
    10 20
    
    # 指定关键字实参时,形参名不要带引号,否则会语法报错。
    func('b'=20,'a'=10)
    SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
    

    可变长实参*和**

    在函数调用时,*会将后面的可迭代对象拆分成位置实参。拆分后的值应与位置形参的数量一致。如果这个可迭代对象为字典,传入函数的值为字典的key。

    def func(a,b,c):
        print(a,b,c)
    func(*[1,2,3])
    1 2 3
    
    func(*{'k1':1,'k2':2,'k3':3})
    k1 k2 k3
    

    在函数调用时,**会将后面的字典(必须是字典)拆分成关键字实参。字典的key必须是形参名。

    def func(a,b,c):
        print(a,b,c)
    
    func(**{'a':1,'c':2,'b':3})
    1 3 2
    

    实参最终顺序

    func(位置实参,关键字实参,*iterable,**dict)
    

    *和**的魔性用法

    在函数嵌套中,外层函数使用*和**接收任意参数,内层函数使用*和**将接收的任意参数拆分。这个方法在装饰器中会使用到。

    def wrapper(*args,**kwargs):  # wrapper先接收为(1,2,3) {'a':4,'b':5},传给inner
        def inner(*args,**kwargs):  # 最后接收到1,2,3,a=4,b=5,再通过*和**聚合为(1,2,3) {'a':4,'b':5}传给args和kwargs
            print(args,kwargs)
        inner(*args,**kwargs)  # 调用inner接收后用*和**拆分为1,2,3,a=4,b=5 传给inner函数。
    
    wrapper(1,2,3,a=4,b=5)
    (1, 2, 3) {'a': 4, 'b': 5}  # 最终输出
    

    在变量解压赋值中,*能将溢出的值聚合成一个列表赋值给后面的变量名,该名约定俗成为下划线 _ 。

    t = (1,2,3,4)
    a, *_ = t
    print(a, _)
    1 [2, 3, 4]
    
    *_, a = t
    print(_,a)
    [1, 2, 3] 4
    
    a, *_, b = t
    print(a, _, b)
    1 [2, 3] 4
    

    函数对象

    函数是第一等公民

    1、函数可以当变量赋值

    def f1():
        print('from f1')
    f2 = f1  # 将f1的内存地址关联给f2
    f2()  # f2加括号也能调用
    from f1
    

    2、可以当做参数传给另一个函数。

    def f1():
        print('from f1')
    
    def f2(x):
        x()
    f2(f1)  # 将f1赋值给x,在f2内调用f1()
    from f1
    

    3、可以当做一个函数的返回值。

    def f1():
        print('from f1')
    
    def f2(x):
        return x
    
    ret = f2(f1)
    
    ret()  # 拿到返回值f1,加括号也能调用
    
    from f1
    

    4、函数可以当做容器类型的元素。

    def func():
        return 100
    
    l1 = [1,2,func]
    
    res = l1[-1]()  # 通过索引取到func,加()能调用
    print(res)
    
    100
    

    通过以上特性,可以写一个函数功能字典。

    def haha():
        print('哈哈')
        
    def hehe():
        print('呵呵')
    
    # 若要添加功能,只需添加函数和功能字典即可,主逻辑代码无需改变。
    def hei():
        print('嘿嘿')
    
    func_dict = {
        '0':['退出'],
        '1':['打印哈哈',haha],
        '2':['打印呵呵',hehe],
        # 添加一个key:value
        '3':['打印嘿嘿',hei],
    }
    
    
    while 1:
        for i in func_dict:
            print(i,func_dict[i][0])
        choise = input('>>>').strip()
        if choise == '0':
            break
        elif choise in func_dict:
            func_dict[choise][-1]()
        else:
            print('更多功能开发中...')
    

    函数嵌套

    嵌套定义

    在函数内再定义函数。

    def wrapper():
        def inner():
            print('from inner')
        return inner
    
    # 通过调用wrapper得到返回值为inner,然后将返回值加()即可调用.
    res = wrapper()
    res()
    from inner
    

    使用嵌套定义,可以写一个同类型多种功能的函数,通过输入参数选择不同的功能。这样在调用时只需知道一个函数的用法即可,而无需调用多个函数。

    例如,写一个计算圆的周长或面积的函数。

    from math import pi
    
    def circle(radius,mode=0):
        def perimiter(radius):
            return 2 * pi * radius
        def area(radius):
            return pi * (radius ** 2)
        # 判断如果mode为0则计算周长,如果为1则计算面积。
        if mode == 0:
            return perimiter(radius)
        elif mode == 1:
            return area(radius)
        else:
        	return 'input 0 or 1'
        
    res = circle(10,mode=1)
    print(res)
    314.1592653589793
    

    嵌套调用

    在一个函数内再调用其他函数。

    例如,写一个比较四个数返回最大数的函数,可以先写一个比较两个数的函数,然后通过调用这个函数来比较四个数。

    def max2(a,b):
        return a if a > b else b
    
    def max4(a,b,c,d):
        ret1 = max(a,b)
        ret2 = max(ret1,c)
        ret3 = max(ret2,d)
        return ret3
    
    res = max4(1,2,3,4)
    print(res)
    4
    

    使用嵌套调用,可以让一个功能复杂的函数拆分成多个功能简单的函数,然后再通过一个函数调用多个简单函数。这样能使代码逻辑更清晰。

  • 相关阅读:
    The formatter threw an exception while trying to deserialize the message in WCF
    通过Web Deploy方式部署WCF
    The Managed Metadata Service or Connection is currently not available
    How to create Managed Metadata Column
    冒泡算法
    asp.net core 实战项目(一)——ef core的使用
    Vue学习笔记入门篇——安装及常用指令介绍
    Vue学习笔记入门篇——数据及DOM
    Vue学习笔记目录
    Chart.js在Laravel项目中的应用
  • 原文地址:https://www.cnblogs.com/ChiRou/p/13419725.html
Copyright © 2011-2022 走看看