• Python:函数基础


    Blog:https://www.cnblogs.com/Rohn

    函数基础

    除了可以直接使用的内置函数外,Python还支持自定义函数,即将一段有规律的、可重复使用的代码定义成函数,从而达到一次编写、多次调用的目的。

    函数的本质就是一段有特定功能、可以重复使用的代码,这段代码已经被提前编写好了,并且为其起一个好听的名字。在后续编写程序过程中,如果需要同样的功能,直接通过起好的名字就可以调用这段代码。

    函数的作用

    • 结构化编程对代码的最基本的封装,一般按照功能组织一段代码;
    • 封装的目的为了复用,减少冗余代码;
    • 代码更加简洁美观、可读易懂

    函数的定义

    Python函数:能完成一定的功能,由若干语句组成的语句块、函数名称、参数列表构成,它是组织代码的最小单元。

    语法格式

    def 函数名(参数1,参数2,参数3,...):
        '''注释'''
        函数体
        return 返回的值
    

    需要注意的地方:

    • 函数名后面必须加冒号;
    • 函数名即标识符,命名规范:小写字母,多个单词用_间隔;
    • 如果函数体和def不在同一行,必须缩进,约定4个空格;
    • 若没有return,则隐式返回一个None值;
    • 如果函数体body语句只有一行,或者可以简写为一行,则可以写在def的同行。例如:
    def myfunc(x,y,z): print(x+y+z)
    

    函数的调用

    如何调用

    函数声明好之后,就可以执行函数,执行函数也称为调用函数,方式为func_name(args),例如:

    myfunc(1,2,3)
    

    调用规则

    函数的使用,必须遵循原则:先定义,后调用

    若在前面调用了,后面再定义,是否会报错呢?

    测试一:

    def bar():
        print('from bar')
    
    def foo():
        print('from foo')
        bar()
    foo() # 正常
    

    测试二:

    def foo():
        print('from foo')
        bar()
        
    def bar():
        print('from bar')
    foo() # 也正常
    

    测试三:

    def foo():
        print('from foo')
        bar()
    
    foo()    
        
    def bar():
        print('from bar')
    # 报错
    NameError: name 'bar' is not defined
    

    函数的返回值

    函数返回值:

    • 没有返回值:默认返回None
    • 返回一个值:函数结束了且返回一个值
    • 返回多个值:多个值之间用逗号隔开,接收的时候可以用一个变量接收(返回元组),也可以用等量的多个变量接收

    什么时候需要有返回值?

    调用函数,经过一系列的操作,最后要拿到一个明确的结果,则必须要有返回值。

    通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果。

    什么时候不需要有返回值?

    调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值。

    通常无参函数不需要有返回值。

    多个返回值

    Python的函数支持返回多个值。返回多个值时,默认以tuple的方式返回。例如,下面两个函数的定义是完全等价的。

    def f():
        return 1,2
    
    def f():
        return (1,2)
    

    丢弃返回值

    # 不进行任何赋值,将丢弃所有返回值
    f()
    
    # 可以通过索引取得某个或某几个返回值
    a = f()[0]
    b = f()[1]
    
    # 使用双下划线__或更多下划线___________
    # 丢弃第二个返回值
    a, __ = f()
    

    函数调用时的***

    除了在def定义函数时,参数中可以使用***收集参数,在函数调用的时候也可以使用***分别解包元组(列表或其它对象)、字典。一定要注意区分函数定义和函数调用时的***,它们的用法是不通用的。

    例如,解包元组:

    def f(a,b,c,d):
        print(a)
        print(b)
        print(c)
        print(d)
    
    T=(1,2,3,4)
    f(*T)
    

    *除了可以解包元组,还可以解包其它可迭代对象,例如列表。甚至是字典也能解包,只不过*解包的字典得到的是key组成的参数列表,和value无关:

    D=dict(a=11,b=22,c=33,d=44)
    f(*D)
    
    # 输出:
    a
    b
    c
    d
    

    **解包的字典则是key=value组成的参数列表。以下是函数调用时使用**进行解包,字典D中的key名称必须和def中定义的参数名称相同:

    def f(a,b,c,d):
        print(a)
        print(b)
        print(c)
        print(d)
    
    D=dict(a=11,b=22,c=33,d=44)
    f(**D)
    
    # 输出:
    11
    22
    33
    44
    

    在函数调用时,可以混合位置参数、关键字参数、*解包参数、**解包参数。用法非常的灵活:

    def f(a,b,c,d):
        print(a)
        print(b)
        print(c)
        print(d)
    
    f(*(1,2),**{'d':4,'c':3})
    
    f(1,*(2,3),**{'d':4})
    
    f(1,c=3,*(2,),**{'d':4})
    
    f(1,*(2,3),d=4)
    
    f(1,*(2,),c=3,**{'d':4})
    
    # 结果如下
    1
    2
    3
    4
    1
    2
    3
    4
    1
    2
    3
    4
    1
    2
    3
    4
    1
    2
    3
    4
    

    上面调用函数时的效果都等同于f(1,2,3,4)

    函数的参数

    函数的参数其实也是变量,只不过这些变量是独属于函数的本地变量,函数外部无法访问。在函数调用的时候,会将给定的值传递给函数的参数,这实际上是变量赋值的过程。例如:

    def myfunc(x,y,z):
        print(x,y,z)
    
    myfunc(1,2,3)
    

    形参和实参

    形参即变量名,实参即变量值,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定。

    形参:定义函数时,小括号中的参数,是用来接收参数用的,在函数内部作为变量使用。

    实参:调用函数时,小括号中的参数,是用来把数据传递到函数内部用的。

    参数的传递

    参数的传递可以分为按指针传参、按位置传参、按关键字key=value方式传参。

    按指针传参

    Python中变量赋值、参数传递都是通过指针拷贝的方式进行的。都只是拷贝了源数据的一个地址,而不会拷贝内存中完整的数据对象副本。所以,如果在函数内部修改变量指向的数据对象,会影响函数外部的数据。

    例如:

    def f(x):
        print(x+3)
    
    
    a = 4
    f(a)
    
    # 输出结果
    7
    

    按位置传参

    如果是多个参数,则按从左到右的顺序进行参数变量的赋值:

    def f(x, y, z):
        print(x)
        print(y)
        print(z)
    
    
    f(2, 3, 4)
    
    # 输出结果
    2
    3
    4
    

    调用f(2,3,4)的时候,会按照从左向右的位置方式对本地变量x、y、z赋值:x=2,y=3,z=4

    按关键字key=value方式传参

    Python还支持key=value的方式设置函数调用时的参数,使用key=value的方式赋值时,顺序不重要。这种函数调用时的传值方式称为关键字传值

    例如:

    def f(x, y, z):
        print(x)
        print(y)
        print(z)
    
    
    f(x=3, y="haha", z=4)
    
    # 输出
    3
    haha
    4
    

    也可以打乱顺序,输出结果不变:

    f(x=3, z=4, y="haha")
    

    还可以将key=value和位置传参的方式进行混合:

    f(3, "haha", z=4)
    

    但混合按位置传参方式的时候,位置参数必须在其它传参方式的前面,不仅此处结合key=value时如此,后文中位置参数结合其它方式传参也都如此:位置参数必须在最前面。例如,下面的传参方式是错的:

    f(z=4, 3, "haha")
    

    参数默认值

    在def或lambda声明函数的时候,可以通过var=default的方式指定参数的默认值。

    例如:

    def f(x=3):
        print(x)
    
    
    f(4)
    f("haha")
    f()
    
    # 输出结果
    4
    haha
    3
    

    上面的f(4)f("haha")都对函数f()的本地变量x进行了赋值。但是最后一个调用语句f()未赋值,而是使用参数的默认值3

    设置参数默认值时,如果函数有多个参数,则带默认值参数后面必须放在最后面。例如:

    # 正确
    def f(x, y, z=4)
    def f(x, y=1, z=4)
    
    # 错误
    def f(x, y=4, z)
    

    只要为参数设置了默认值,那么调用函数的时候,这个参数就是可选的,可有可无的,如果没有,则采用默认值。

    def f(x, y=2, z=4):
        print(x)
        print(y)
        print(z)
    
    
    # 不采用任何默认值
    f(2, 3, 4)
    
    # 采用z的默认值
    f(2, 3)
    
    # 采用y的默认值
    # 此时z必须按key=value的方式传值
    f(2, z=5)
    
    # y、z都采用默认值
    f(2)
    
    # 输出结果
    2
    3
    4
    2
    3
    4
    2
    2
    5
    2
    2
    4
    

    位置可变参数*

    对于任意长度的参数,可以在def声明的函数中使用*将各位置参数收集到一个元组中。

    def f(*args):
        print(args)
    
    
    f(1, 2, 3, 4)
    
    # 结果输出:(1, 2, 3, 4)
    

    上面调用f(1, 2, 3, 4)的时候,将所有参数都收集到了一个名为args的元组中。

    既然是元组,就可以对参数进行迭代遍历:

    def f(*args):
        for arg in args:
            print(arg)
    
    f(1,2,3,4)
    
    # 输出结果
    1
    2
    3
    4
    

    必须注意,*是按位置收集参数的。

    def f(x, y, *args):
        print(x)
        print(y)
        for arg in args:
            print(arg)
    
    
    f(1, 2, 3, 4)
    

    按照从左向右的传参规则,首先将1赋值给x,将2赋值给y,然后将剩余所有的位置参数收集到args元组中,所以args=(3,4)

    如果*后面还有参数,则调用函数的时候,后面的参数必须使用key=value的方式传递,否则会收集到元组中,从而导致参数缺少的问题:

    def f(x, *args, y):
        print(x)
        print(y)
        for arg in args:
            print(arg)
    
    
    # 正确
    f(1, 3, 4, y=2)
    
    # 错误
    f(1, 2, 3, 4)
    

    上面调用f(1, 3, 4, y=2)的时候,会按照位置参数对x赋值为1,然后将所有位置参数收集到元组args中,因为y=2是非位置参数传值方式,所以args=(3, 4)

    如果为上面的y设置默认值:

    def f(x, *args, y=2)
    

    那么f(1, 2, 3, 4)会将(2, 3, 4)都收集到元组args中,然后y采用默认值2

    关键字可变参数**

    除了可以使用*将位置参数收集到元组中,还可以使用**key=value格式的参数收集到字典中。

    例如:

    def f(x, **args):
        print(x)
        print(args)
    
    
    f(1, a=11, b=22, c=33, d=44)
    

    既然是将参数收集到字典中,就可以使用字典类的工具操作这个字典。例如,遍历字典。

    **的后面不能出现任何其它类型的参数。例如,下面的都是错误的def定义方式:

    def f(x, **args, y)
    def f(x, **args, y=3)
    def f(x, **args, *t)
    

    只能将位置参数或者*的收集放在**的前面。

    def f(x, y, **args)
    def f(x, *args1, **args2)
    

    keyword-only参数形式

    keyword-only的参数传值方式表示def中如果使用了*,那么在调用函数时,它后面的参数必须只能使用关键字传值。其实在前面的内容中已经出现过几次与之相关的说明。

    另外注意,*才是keyword-only开关,**不是,虽然**也有自己的一些语法限制:任意类型的参数定义都必须在**之前,包括keyword-only类型的参数。例如:

    def f(a, *b, c):
        print(a, b, c)
    

    按照keyword-only的规则,被*b收集的位置参数不包括c,这个c必须只能使用关键字的方式传值,否则就被当作位置参数被收集到元组b中。

    # 正确
    f(1, 2, 3, c=4)
    
    # 错误
    f(1, 2, 3, 4)
    
    # 错误
    f(1, c=4, 2, 3)
    

    其中最后一个错误和如何def的定义无关,而是函数调用时的语法错误,前面已经解释过:位置参数必须放在最前面。

    还可以直接使用*而非*args的方式,这表示不收集任何参数,但却要求它后面的参数必须按照关键字传值的方式。

    def f(a, *, b, c):
        print(a, b, c)
    

    以下是正确和错误的调用方式示例:

    # 正确
    f(1, b=2, c=3)
    f(1, c=3, b=2)
    f(b=2, c=3, a=1)
    
    # 错误
    f(1, 2, 3)
    f(1, 2, c=3)
    f(1, b=2, 3)
    

    不过,keyword-only后面的参数可以使用参数默认值。

    def f(a, *, b, c=3)
    

    那么c是可选的,但如果给定,则必须按关键字方式传值。

  • 相关阅读:
    IIS下配置跨域设置Access-Control-Allow-Origin
    Arcgis去除Z,M值
    GIS开发之数据查询
    GIS开发之计算四参数,七参数
    Openlayer3之绚丽的界面框架-Materialize
    Openlayer3之C++接口在javaScript的封装使用
    Windows环境和Linux环境下Redis主从复制配置
    Centos 7 安装和配置Redis
    .net手动编写Windows服务
    SQL获取当前日期的年、月、日、时、分、秒数据
  • 原文地址:https://www.cnblogs.com/Rohn/p/13347859.html
Copyright © 2020-2023  润新知