当前位置:脚本大全 > > 正文

python函数基本操作(Python定义函数功能与用法实例详解)

时间:2021-10-21 07:06:23类别:脚本大全

python函数基本操作

Python定义函数功能与用法实例详解

本文实例讲述了python定义函数功能与用法。分享给大家供大家参考,具体如下:

1.函数的意义

一般数学上的函数是,一个或者几个自变量,通过某种计算方式,得出一个因变量。
y = f(x)

在python中,为了使操作更加简洁,就引入了函数这个概念。

python中的函数,可以把一大串要反复使用的代码“定义”(封装)成一个函数,给予这个函数一个标识符作为函数名,设置自变量和因变量。然后要使用这一大串代码的时候,就调用这个我们自己创造的函数,输入自变量,然后会返回给我们因变量。

2.函数的定义

在python中,对应数学函数的自变量和因变量的值,叫做参数和返回值。

用def来定义一个函数,下面是一个通用的模型,函数都这么定义:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • def 函数名(参数列表):
  •   ...
  •   代码块
  •   ...
  •   return 返回值
  • 然后举一个例子,假设我们要判定一个学生的成绩是及格还是不及格:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • def judge_score(score):
  •   judge = none
  •   if score >= 60:
  •     judge = true
  •     print('pass')
  •   else: #虽然成绩应该在0-100之间,但是我懒,就不限定范围了。
  •     judge = false
  •     print('fail')
  •   return judge
  • 然后试一下:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • judge_score(59)
  • fail
  • j = judge_score(61)
  • pass
  • print(j)
  • true #说明j接收到的值为true
  • 这段代码很简单,但是也不能每次要判断一次成绩,就敲出这么一大串,所以为了便捷,就给这段代码用def(define,定义)封装成一个函数。

    给一个函数名judge_score,后面调用就可以用judge_score()

    score是我们要输入的自变量,也就是要在这个judge_score()中进行运算的值。

    接下来要注意:

    这个'pass'和'fail' 不是函数的返回值!
    这个'pass'和'fail' 不是函数的返回值!
    这个'pass'和'fail' 不是函数的返回值!

    ‘pass'和'fail' 是函数内部的print()打印出来的内容,函数的返回值是写在return后面的内容。

    return后面可以做运算,也可以直接写变量。如果这个函数的语句块内没有写return语句,那么说明没有定义返回值,也就是说调用函数什么都没有返回,如果拿一个标识符来接受这个函数的返回值,只能接受到none。

    return后面的返回值可以是多个,多个的话,就用,隔开,然后封装成一个元组再返回。

    函数名也是标识符,有的时候可以用callable()来判断这个标识符是不是一个可以调用的。

  • ?
  • 1
  • callable(judge_score) #返回值为true
  • 注意别再检查的函数名标识符后面加()。

    3.函数的参数

    在定义函数时,函数名后面的()里面叫做参数列表,这个参数列表里的参数,都是要在下面的代码块中要使用的。

    3.1 形式参数和实际参数

    形式参数,就是指在定义函数时,参数列表里写出的参数,他们都还只是标识符,都会在下面的代码中出现。此时此刻他们没有具体的值,只是一个“外壳”,所以叫形式参数。
    比如y = 3x 里面这个x,只是一个形式,没有具体的值。

    实际参数,是指在调用参数时,函数名后面的括号内给出具体的值,每个值都会与某一个形式参数对应。这些值是存在的,不止有个外壳。也可以算作是数学函数中的自变量,用它们来计算出因变量。比
    如y = 3x ,假设x=3,这个3就是实际参数。

    注意,每一个形式参数都必须获得一个值(如果没有默认值),才能进行计算,否则会报错!

    3.2 传递参数的类型和参数的类型

    3.2.1 传递参数类型

    传递参数,我的理解就是把实际参数和形式参数连接起来。

    定义一个函数bmi,用来计算人的body mass index:

  • ?
  • 1
  • 2
  • 3
  • def bmi(height, weight):
  •   index = "%.2f" % (weight / (height**2)) #留两位小数
  •   return index
  • 位置传参

    调用它:

  • ?
  • 1
  • bmi(1.71, 65) #返回值为22.23
  • 可以看到我们的形式参数有height和weight,实际参数是1.71和65。在调用函数时,这两个实际参数没有指定谁是height,谁是weight,是按定义函数时,参数列表里面的形式参数的位置一一对应起来。这样就叫做位置传参。

    关键词传参

    调用它:

  • ?
  • 1
  • bmi(weight=65, height=1.71) #返回值22.23
  • 如果函数的调用者知道形式参数的标识符,也可以直接用 形式参数名=值 这样的方式来传递参数,可以理解为赋值。因为是用关键字传递参数,所以位置可以和定义函数时参数列表内的形式参数顺序不同。

    混合传参

    有的时候,我们可能有一些参数要用位置传参,有一些要用关键字传参。万幸的是他们可以混合使用。但是要遵守一定的规则:

  • ?
  • 1
  • bmi(1.71, weight=65) #返回值为22.23
  • 前面的1.71用的是位置传参,后面65用的是关键词传参。

    注意,关键字传参一定要写在位置传参之后!不然就会报错。

    3.2.2 参数类型

    位置参数的可变参数

    比如有这样一个需求,要输入若干个数字,然后求出这若干个数字中的最大值和最小值。分析一下,若干个数字,也就是不知道数字的个数,这样也就不知道设置多少个形式参数。这样就可以用,*args,可变参数。

    如果在定义函数时*args的左侧有参数,那么在调用时,实际参数依次给予*arg左边的用位置传参的普通形式参数之后,剩下的实际参数无论多少都会被*args接收,和切片有一定的相似之处,但是差别也不小。

    举个例子

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • def maxmin(x,*nums): #这个x是为了显示*args的收取范围
  • length = len(nums)
  • for i in range(1,length): #这是选择排序的思路,走一趟,练练手
  •   maxindex = 0
  •   minindex = 0
  •   if nums[i] > nums[maxindex]:
  •     maxindex = i
  •   if nums[i] < nums[minindex]:
  •     minindex = i
  • print('x={};{};max:{};min:{}'.format(x,nums,nums[maxindex],nums[minindex]))
  • 调用这个函数:

  • ?
  • 1
  • 2
  • maxmin(100,12,23,34,45,67,9)
  • x=100;(12, 23, 34, 45, 67, 9);max:12;min:9
  • 可以看出,在给出的实际参数中,除了第一个100,被x接收了,剩下的实际参数都被*nums接收了,然后封装成了一个元组(讲道理,用逗号隔开了又被一个标识符接收,确实应该封装成元组)。

    注意,和切片不同的是,定义函数时*args会无限接收实际参数,不会给后面的形式参数留值,所以在定义函数时的参数列表里,位置参数的可变参数一定要在普通位置参数之后!

    关键字参数的可变参数

    关键字参数的可变参数,不是收集多个用关键字传参的实际参数,而是收集关键字传参的关键字和值,并把他们当做一个键值对,收集在一个字典内,在代码块中使用。

  • ?
  • 1
  • 2
  • 3
  • 4
  • def test(x=1,**nums):
  •   print(x,nums)
  • test(c=3,x=2,a=1,b=2)
  • 2 {'c': 3, 'a': 1, 'b': 2}
  • 可以看出,用关键字传参,可以不按位置顺序来,先把
    关键字参数的可变参数,和位置参数的可变参数一样,会无限接收实际参数,不过是接收实际参数的关键字和值,组成键值对。

    3.3 默认参数

    有的时候,一些参数变化不频繁,以上面定义的这个bmi函数来看,假设一个班里面的99%的同学,身高变化很大,体重都是75kg,每次用这个函数算同学的bmi,都要重新输入一遍身高体重,比较麻烦,所以可以在定义函数时,给形式参数设置一个默认值:

  • ?
  • 1
  • 2
  • 3
  • def bmi(height=1.80, weight=75):
  •   index = "%.2f" % (weight / (height**2)) #留两位小数
  •   return index
  • 注意,这是在定义函数时,就设置好默认值,然后调用:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • bmi(1.80) #此时按height=1.80,weight=75来计算
  • bmi(1.71) #此时按height=1.71,weight=75来计算
  • bmi(65) #此时按height=65,weight=75来计算,注意和上面的区别
  • bmi(1.71, 65) #此时按height=1.71,weight=65来计算
  • bmi(height=1.90) #此时按height=1.90,weight=75来计算
  • bmi(1.80, weight=80) #此时按height=1.80,weight=80来计算
  • 也就是说,如果没有传参,那么形式参数就会按定义参数时设置的默认值来计算。

    如果用位置传参,就按形式参数的位置顺序,依次往后覆盖,如果实际参数没给够,那么没有接收到位置传参的形式参数就会用默认值。(也就是说,在定义函数时,虽然设置了默认值,看起来和关键字参数似的,但是它也是有前后位置顺序的。)

    如果用关键字传参,理解就比较简单了,如果给了,就用关键字传参给的实际参数,如果没给,就用默认值。

    总之,如果普通的形式参数没有设置默认值,就必须要接收一个实际参数来使用。如果形式参数在定义时设置了默认值,调用函数时,没有给出实际参数,就用默认值,如果给了一个实际参数,就用这个新的实际参数把默认值覆盖。

    3.4 keyword-only参数

    这个参数可以理解为,必须用关键字传参才能获得的参数。

    这种参数为了区别于普通的形式参数,位置有所改变,在定义参数时,放在*args(位置参数的可变参数)和**kwargs(关键字参数的可变参数)之间,就代表这个参数是keyword-only参数。

  • ?
  • 1
  • 2
  • def test(*words, x):
  •   print(words, x)
  • 调用这个函数:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • test(1, 2, 3, 4)
  • #这样会报错,因为这四个都是位置传参,都被*word截获了,x没有值
  • test(1, 2, 3, x=4) #这个没毛病
  • (1, 2, 3) 4
  • test(x=4) #这个也没毛病,*word一个值都有截获
  • () 4
  • 注意,在定义函数时,参数列表里,keyword-only参数不能放在关键字参数的可变参数之后,因为keyword-only参数要用关键字传参,**kwargs要截获所有的关键字传参的实际参数,keyword-only参数永远也收不到值。

    keyword-only参数还有另一种定义形式,比如,我们想要这个函数都用关键字传参,并且不想接收任何位置传参的实际参数(就是一用位置传参就报错),可以用一下这种形式:

  • ?
  • 1
  • 2
  • def test(*, x, y):
  •   print(x,y)
  • 调用它:

  • ?
  • 1
  • 2
  • 3
  • test(1, x=100, y=99) #会报错,因为1没有形参来接收它
  • test(x=100, y=99) #没毛病
  • 100 99
  • 3.6 参数列表的顺序***

    重中之重:
    定义函数时:(位置参数,带缺省值的位置参数,位置参数的可变参数,keyword-only参数,关键字参数的可变参数)
    调用函数时:(用位置传参的实际参数,用关键字传参的实际参数)

    但是一定要确保,定义函数时,参数列表里的每一个参数(可变参数除外,因为可变参数可以收集到0个实际参数)都要有值可以使用。

    例:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • def test(a,b,c,d=5,*nums,x='x',y='y',**ddict):
  •   print(a,b,c,d)
  •   print(nums)
  •   print(x,y)
  •   print(ddict)
  • 调用它:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • test(97,98,99,100,101,102,x='xx',y='yy',name='tom',age=10)
  • 97 98 99 100
  • (101, 102)
  • xx yy
  • {'name': 'tom', 'age': 10}
  • 可以看到,有六个用位置传参的实际参数,虽然d有默认值,但是按位置来看,d也会接收到一个新的值100,因此nums只截获了两个位置参数。

    然后是keyword-only参数,x和y,都得用关键字传参。如果x和y不指定的话,就会使用默认值x='x',y='y'。

    然后是关键字参数的可变参数,不能说是截获,得说keyword-only参数只给它剩下了两个,然后他们组成了一个字典

    还要注意,在传参的时候,位置传参要放在最前面。然后是关键字传参,从关键字传参中把keyword-only参数挑走,然后剩下的给**kwargs。

    3.5 实际参数的解构

    有时候,定义参数的时候,有很多形参。但是实际参数,都存在一个list或者说别的数据结构中,一个个拿出来很麻烦,所以可以种参数解构来完成:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • def maxmin(x,*nums):
  •   length = len(nums)
  •   for i in range(1,length):
  •     maxindex = 0
  •     minindex = 0
  •     if nums[i] > nums[maxindex]:
  •       maxindex = i
  •     if nums[i] < nums[minindex]:
  •       minindex = i
  •   print('x={};{};max:{};min:{}'.format(x,nums,nums[maxindex],nums[minindex]))
  • 这个函数,是找若干个数中的最大值还有最小值的,它可以接受若干个值(因为定义函数时用的是*args)。但是如果给我们的是一个列表,那还真把每个元素都提取出来,输入一遍吗,太蠢了,可以直接在调用函数的时候解构。

    用*解构:

  • ?
  • 1
  • 2
  • 3
  • lst = [100, 12, 23, 34, 45, 67, 9]
  • maxmin(*lst)
  • 100 9
  • 再看一个例子,用**解构:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • def test(*nums):
  •   print(nums)
  • test({'a':1,'b':2,'c':3})
  • ({'a': 1, 'b': 2, 'c': 3},) #打印出来一个元组,说明传入的字典没有解构
  • test(*{'a':1,'b':2,'c':3})
  • ('a', 'b', 'c') #打印的是key,字典解构是key的集合,没毛病
  • ?
  • 1
  • 2
  • 3
  • 4
  • def test(a,b,c): #因为要接字典解构出来的
  •   print(a,b,c)
  • test(**{'a':1,'b':2,'c':3}) #**这样是把字典里的键值对解构出来
  • 1 2 3
  • 4. 函数的返回值

    在一些已经知道函数中,有的有返回值,比如input()sorted()等,它们都可以用一个标识符来接收,形成一个变量。有的没有返回值,比如print()list.append()等方法,都是没有返回值的。

    在自定义函数中,也能做到这一点,用的是return语句:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • def test(x=5):
  •   a = x ** 2
  •   print(a)
  • b = test()
  • 25 #这个25是print(a)的效果
  • b
  • none
  • 这说明,我们定义的函数test(),它是没有返回值的,虽然出现了结果,但那时print()语句的打印输出,用标识符来接收test()的输出,什么都接收不到(什么都没有就是none)。

    如果用return语句:

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • def test(x=5):
  •   a = x ** 2
  •   print(a)
  •   return a
  • b = test()
  • 25 #这个还是print(a)的打印输出
  • b
  • 25 #这个是b刚刚接收函数的返回值
  • 也就是说return语句后面的值,可以作为这个函数的返回值,这个值可以是一个变量,也可以是一个表达式,还可以写多个用逗号隔开的值,不过最后会被封装成一个元组返回。

  • ?
  • 1
  • 2
  • 3
  • 4
  • def test():
  •   ....
  •   return 1, 2, 3, 4 #返回值其实是(1, 2, 3, 4)
  • a, b, c, d = test() #这里用解构来接收返回值,会比较方便
  • 如果写了return语句,return后面的值会作为返回值输出,但是如果不写return语句,或者只写了一个return,后面没有值,就说明这个函数没有返回值(其实是隐式调用了return = none)

    自定义函数中,可以有多条return语句,在定义时候不会报错,但是这些return语句只有一条会被执行,执行完这个return语句,函数就结束,其不会理会其他的return语句。

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • def comparethree(n):
  •   if n > 3:
  •     return 3
  •   else:
  •     标签:

    猜您喜欢