欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

9 - Python函数定义-位置参数-返回值

程序员文章站 2022-06-25 18:44:24
...

1 函数介绍

        函数在编程语言中就是完成特定功能的一个词句组(代码块),这组语句可以作为一个单位使用,并且给它取一个名字。可以通过函数名在程序的不同地方多次执行(这叫函数的调用)。函数在编程语言中有基本分为:预定义函数,自定义函数。预定义函数可以直接使用,而自定义函数顾名思义需要我们自己定义函数。

在数学中的定义,这里就不介绍了。因为没卵用。哈哈

1.1 为什么要使用函数

在编程中使用函数主要有两个优点:

  1. 降低编程难度:通常将一个复杂的大问题分解成一系列的小问题,然后将小问题划分成更小的问题,当问题细化为足够简单时,我们就可以分而治之,各个小问题解决了,大问题就迎刃而解了。
  2. 代码重用:避免重复劳作,提供效率
  3. 代码更加简洁美观,可读性增加

1.2 Python中的函数

        在Python中,函数由若干语句组成代码块函数名称参数列表构成,它是组织代码的最小单元,使用函数可以完成一定的功能,在Python中函数主要分为三类:内置函数第三方函数库自定义函数。常用的内置函数在前面已经介绍,第三方函数库需要先引入模块,通过模块调用,在模块学习中进行介绍,这里主要说的是如何自定义一个函数。

2 函数的基本使用

        在Python中,定义一个函数要使用def语句,依次写出函数名括号括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。下面是一个函数的基本结构

def 函数名(参数列表):
    函数体(代码块)
    [return 返回值]   # 函数可以无返回值

注意:

  • 函数名就是标识符,命名要求一样
  • 语句块必须缩进,约定4个空格
  • Python的函数没有return语句,隐式会返回一个None
  • 定义中的参数列表成为形式函数,只是一种符号表达式(标识符),简称形参
    我们以自定义一个求绝对值的函数为例:
定义:
def abs(x):    
    if x >= 0:
        return x
    else:
        return -x

调用:
    abs(-10)

上面只是一个函数的定义,j具体来看一下各个部分的解释:

  • 函数名字叫做abs,接受1个形式参数x。
  • return x:表示要返回的值是x,函数可以无返回值。
  • 函数是一个可调用对象,函数名加括号就表示调用。
  • 和变量是的使用方式相同,在使用函数时,需要预先进行定义。
  • 直接打印函数名,不会触发函数的执行,反而会打印函数的内存地址。

我们自定义的函数abs,由于与内置函数重名,那么将会覆盖掉内置函数,所以请谨慎命名。

        函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。如果没有return语句,函数执行完毕后会隐士的返回None。如果我们确实要return None可以简写为return,或者不写return语句(会让人看不懂,建议只写return)。
        调用函数,那么只需要使用函数名加括号,就能执行,但如果函数定义了参数,那么必须在执行的时候传递参数给函授,否则会报异常!关于调用我们还需要了解:

  1. 函数定义,只是声明了一个函数,它不会被执行,调用时才会执行
  2. 调用方式就是函数名后加上小括号,如果有必要需要在括号内写上参数
  3. 调用时写的参数是实际参数,是实实在在传入的值,简称实参

函数是可调用对象,可以使用callable()进行判断

In [1]: def abs(x):
   ...:     if x >= 1:
   ...:         return x
   ...:     else:
   ...:         return -x

In [2]: callable(abs)     # 函数是可调用的,注意这里不能对函数加括号,那么callable判断的就是函数的返回值是否可以执行了
Out[2]: True

In [3]: a = '123'
In [4]: callable(a)    # 字符串是不可调用的
Out[4]: False

3 函数的参数

        定义函数的时候,括号中指定的就是函数的参数(形式参数),当我们调用函数时,需要将数据进行传递,这种传递参数的方式就叫做传参,严格来说函数只可以使用两种方式:位置传参关键字传参

  1. 位置传参:按照参数定义顺序传入实参
  2. 关键字传参:使用形参的名字来传入实参的方式

需要注意的时:参数传递时如果使用形参的名字,那么传入参数的顺序就可以和定义的顺序不同,当位置传参和关键字传参混用时,位置传参必须放在关键字传参前面传入

定义函数function:
In [1]: def function(x,y):
   ...:     result = x + y
   ...:     return result
   ...:

位置传参:
In [2]: function(1,2)    # 1对应x,2对应y。
Out[2]: 3

关键字传参:
In [3]: function(y=1, x=2)   # 使用关键字时,参数可以不用按照位置顺序。
Out[3]: 3

混合传参:
In [8]: function(1, y = 3)    # 混用时,关键字参数必须要再位置参数右边
Out[8]: 4

3.1 参数的默认值

        在定义形式参数时,为参数指定对应的值,就叫做参数的默认值,当定义了参数的默认值以后,我们传参时可以选择传递该参数的值,也可以选择不传递,当不传递此参数的值时,该参数就使用指定的默认值否则将会使用传递的值

参数默认值也属于位置参数,只不过是给位置参数定义了默认值。

In [9]: def function(x = 10, y = 20):
   ...:     return x + y
   ...:

In [10]: function(2)   # 2会以位置参数的形式传递给x,y没有传递,会使用默认值
Out[10]: 22

In [11]: function(y=100)  # x没有传递,会使用默认值
Out[11]: 110

In [12]: function(x=100)  # y没有传递,会使用默认值
Out[12]: 120

In [13]: function(20, y=500)  # 20以位置参数的形式传递给x,500以关键字参数的形式传递给了y
Out[13]: 520

当定义参数的默认值时,注意默认值参数必须要放在位置参数的右边

In [1]: def functions(x=1, y):    # 必须把x=1,放在y的右边,否则无法完成函数定义
   ...:     print(x+y)
  File "<ipython-input-1-ea496fa7fc81>", line 1
    def functions(x=1, y):
                 ^
SyntaxError: non-default argument follows default argument

使用默认值参数的好处是:

  • 参数的默认值可以在未传入足够的实参的时候,对没有给定的参数赋值为默认值。
  • 参数非常多的时候,并不需要用户每次都输入所有的参数,简化函数调用。

3.2 可变参数

        可变参数顾名思义表示参数的数量是可变的,并且可以使用一个形参匹配任意个实参。针对传递参数方式的不同又分为可变位置传参可变关键字传参

3.2.1 可变位置传参

        在形参前使用*号,表示该形参是可变参数,可以接受多个实参,在函数内部,可变参数会封装成元祖(即便是没有传递)

In [15]: def function(*nums):
    ...:     print(nums)
    ...:

In [16]: function(1,2,3,4)  # 多个参数会被nums收集
(1, 2, 3, 4)

In [18]: function([1,2,3,4])  # 会把list收集成元祖类型
([1, 2, 3, 4],)

在函数定义时,一般的规范是使用 *args, 表示收集多个位置传参。

3.2.2 可变关键字传参

        在形参前使用**号,表示该形参是可变关键字参数,可以接受多个关键字参数,在函数内部,可变关键字参数会封装成字典(即便是没有传递)

In [20]: def function(**kwargs):
    ...:     print(kwargs)
    ...:

In [21]: function(a=1,b=2)
{'a': 1, 'b': 2}

# 参数的默认值和位置参数同时使用
In [5]: def function(x=1,y=2,**kwargs):
   ...:     print('x = {}'.format(x))
   ...:     print('y = {}'.format(y))
   ...:     print(kwargs)
   ...:

In [6]: function(a=10,b=20)   # 参数没有a,b形参,则被kwargs接收
x = 1
y = 2
{'a': 10, 'b': 20}

In [7]: function(x=100,y=200,z=300) # z没有被匹配,被kwargs接收
x = 100
y = 200
{'z': 300}

In [8]: function(1000,2000,z=300)  # 前面的按照位置参数赋值,z同样被字典kwargs收集
x = 1000
y = 2000
{'z': 300}

In [9]:

3.2.3 可变参数混合使用

        前面说的各种参数是可以混合使用的,当混合使用时遵循一定的顺序,简单总结一下,按照从左至右的顺序来说:位置参数,默认值参数,可变位置参数,可变关键字参数:def function(位置参数,默认值参数,可变位置参数,可变关键字参数)

无论如何,顺序不能颠倒

In [9]: def function(x,y,z=1,*args,**kwargs):  # x,y,z都为位置参数,z的默认值为1,*args收集额外的位置传参,kwargs收集额外的关键字传参
   ...:     print(x,y,z)
   ...:     print(args)
   ...:     print(kwargs)
   ...:

In [10]: function(1,2,3,4,5,a=1,b=2)
1 2 3
(4, 5)
{'a': 1, 'b': 2}

3.2.4 可变参数小结

针对可变参数以及不同的混用方式可以有如下结论:

  • 分为位置可变参数关键字可变参数
  • 位置可变参数在形参前使用一个星号*
  • 关键字可变参数在形参前使用两个星号**
  • 可变位置参数和可变关键字参数都可以收集若干个实参,可变位置参数收集形成一个tuple可变关键字参数收集形成一个dict
  • 混合使用参数的时候,在定义阶段要遵循如下顺序:位置参数默认值参数可变位置参数可变关键字参数

当位置传参和关键字传参同时使用时,不可以重复赋值!,这一点使用的时候很重要。

3.3 keyword-only参数*

        Python3的函数参数中,新增了keyword-only参数,什么叫keyword-only参数?我们说当在一个星号参数(可变位置参数)后,出现的普通参数,我们称它为keyword-only参数,因为多余的位置参数都会被*args收集,只能通过keyword的方式对这些形参进行赋值,所以它们只能使用’关键字传参’。

In [11]: def function(a,b,c=1,*args,x,y=2,**kwargs):     # x,y是keyword-only参数,其中y存在默认值,可以不用传递,x必须使用关键字的方式进行传递
    ...:     print(a,b,c)
    ...:     print(args)
    ...:     print(x,y)
    ...:     print(kwargs)
    ...:

In [12]: function(100,200,300,400,d=100,e=200)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-12-cf60009e3d1f> in <module>
----> 1 function(100,200,300,400,d=100,e=200)

TypeError: function() missing 1 required keyword-only argument: 'x'

In [13]: function(100,200,300,400,d=100,e=200,x=500)
100 200 300
(400,)
500 2
{'d': 100, 'e': 200}

特殊形式:

In [17]: def function(*,x,y):   
    ...:     print(x,y)
    ...:

In [18]: function(1,2,3,x=100,y=200)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-18-7d07ae79c088> in <module>
----> 1 function(1,2,3,x=100,y=200)

TypeError: function() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given


In [20]: function(x=100,y=200)
100 200

这里*表示不接受位置传参,只能使用关键字对参数进行赋值

注意:使用了keyword-only参数,那么在定义形参的时的顺序就有所改变了,它们是:位置参数,默认值参数,可变位置参数,keyword-only参数,可变关键字参数

3.4 参数解构

前面我们说过Python的封装与结构,这里的参数也可以利用这种思想进行结构,现有如下函数:

In [21]: def add(x=1,y=2):
    ...:     print(x+y)
    ...:

In [22]: t = (10,20)

In [23]: add(t[0],t[1])   # 将元祖的元素1和元素2分别传给X,y
30

In [24]: add(*t)  
30

In [25]: d = {'x':100, 'y':200}
In [30]: add(**d)
300
  • 将t在传递参数时结构为10,20,作为位置传参传递给add函数
  • 将d在传递参数时结构为x=100,y=200,作为关键字传参传递给函数
  • 这种方法在后面函数的调用过程中非常常用

现在再来回头看一下,什么时参数解构?

  1. 给函数提供实参的时候,可以在集合类型前使用*或者**,把集合类型的结构解开,提取出所以的元素作为函数的实参。
  2. 非字典类型使用*解构成位置参数
  3. 字典型使用**解构成关键字参数
  4. 提取出来的元素数目要和参数的要求匹配,也要和参数的类型匹配,否则请使用*args,**kwargs
In [31]: def add(a,b,*args,m,n,**kwargs):
    ...:     print(a+b+m+n)
    ...:

In [32]: dic = {'a':100,'b':200}
In [33]: add(**dic,m=300,n=400,x=1000)
1000

4 函数的返回值

        我们通常编写函数除了代码可以复用,更多的时候需要的是知道函数的运算结果,那么函数把运算的结果返回给我们,这个结果就叫作做函数的返回值。使用return关键字进行返回。

# 返回1个数据
In [34]: def add(x,y):
    ...:     result = x + y
    ...:     return result
    ...:

In [35]: a = add(10,20)
In [36]: print(a)
30

# 返回多个数据
In [37]: def add(x,y):
    ...:     result = x + y
    ...:     test = x * y
    ...:     return result,test
    ...:

In [38]: a = add(10,20)
In [39]: print(a)
(30, 200)

# 多个return语句
In [40]: def add(x,y):
    ...:     if x > 10:
    ...:         return y
    ...:     else:
    ...:         return x
    ...:

In [41]: a = add(10,20)
In [42]: print(a)
10

总结:

  1. Python函数使用return语句返回"返回值"
  2. 所有函数都有返回值,如果没有return语句,隐式调用return None
  3. return语句并不一定是函数的语句块的最后一条语句
  4. 一个函数可以存在多个return语句,但是只有一条可以被执行,如果没有一条return语句被执行,隐式调用return None
  5. return None可以简写为return
  6. 函数执行到return就会返回,所以return后面的语句永远不会被执行
  7. return可以理解为,结束当前函数计算,返回值!

多个返回值会被包装成一个tuple进行返回,所以函数永远只能返回一个数据

上一篇: 函数

下一篇: PyCharm | def