Python函数


2022年1月3日, Learn eTutorial
2211

在本教程中,您将通过 Python 中的示例全面掌握函数;什么是函数、函数在程序中的重要性、不同类型的函数、如何定义和调用函数、不同类型的参数等。此外,您还将从初学者到专家的水平,涵盖 Python 中变量作用域和递归的概念。

什么是函数?

函数本质上是一个独立的代码块,用于执行特定任务或一组相关任务。函数主要分为两种类型。它们是:

  1. 内置函数
  2. 用户自定义函数

在之前的教程中,您已经看到了许多内置函数的例子,例如 len()max() 等。内置函数是 Python 内置的函数,最终用户可以访问它来执行他们想要的特定任务。另一方面,用户自定义函数是由用户定义的函数,用于执行特定任务。

接下来,您将学习创建和执行自己的函数。在此之前,让我们讨论一下在 Python 程序中使用函数的好处。

函数在程序中的重要性

由于以下合理的原因,函数在所有编程语言中都扮演着至关重要的角色。

  • 提高程序可读性
  • 以紧凑的方式实现代码重用
  • 模块化——将复杂的程序分解成更小的块
  • 避免冗余
  • 最大限度地减少出错的机会

如何定义一个函数?

函数的基本语法如下所示。


def < function_name >(< parameter(s) >):
  “ “ “ Doc_String ” ” ”
   < function _body >
   return(< expression >)
 

上述函数定义的组成部分列表如下。

组成部分 描述
def 关键字 def 定义函数头的开始
< 函数名 > 应为有效的标识符(参考标识符规则)。
< 参数 > 用于向函数传递值。可选。
: 表示函数头的结束
“ “ “ 文档字符串 ” ” ” 用于提供函数文档。可选。
< 函数体 > 遵循相同缩进级别的有效 Python 语句
return 返回函数的值。可选。

一个函数示例,演示如何打印圆的面积


def area_calc():
 """this function gives the area of different shapes"""
pi =3.14
r = 10
print('Area is :',a)
 

在上面的示例中,我们定义了一个打印圆面积的函数。在进行函数调用之前,它不会执行。函数定义在解释器找到函数调用之前一直处于非活动状态。

如何调用一个函数?

函数调用是 Python 函数的另一个重要组成部分。一旦函数创建完成,我们需要通过从另一个函数、程序或 Python 提示符中调用它来执行该函数。要调用函数,请使用以下语法

Python 函数调用语法


< function_name >(< argument(s) >) 
 

在这里,在函数调用中,参数指的是传递给函数的值。函数调用中的参数与函数定义中的参数是同义的。我们可以将参数部分留空,但在函数调用和函数定义中都必须有括号。

函数调用示例


# this is the function definition
def area_calc(r):
 """this function gives the area of circle"""
 pi = 3.14
 a = pi*r*r
 print('Area is :',a)

#This illustrates function call
area_calc(10)
area_calc(20)
 

输出


Area is : 314.0
Area is : 1256.0

在这个例子中,area_calc(10) 和 area_calc (20) 是带有参数 10 和 20 的函数调用。

函数在 Python 中如何工作

到目前为止,在本教程中,我们详细讨论了 Python 函数中使用的所有组件。现在让我们学习函数的整体工作原理和执行顺序。

Python Function working

程序中的函数只有在被调用时才会激活。函数调用将控制权传递给函数,函数通过执行函数体来执行特定任务。当遇到 return 语句时,最终结果将返回给函数调用,否则它会在函数中输出结果并立即终止函数。

注意:参数在 Python 中通常表示为 arg 或 args。

Python 函数参数

函数的另一个重要组成部分是参数。参数在函数名之后、括号内定义。参数应使用逗号分隔,参数的数量不受任何限制。

在前面的示例中,area_calc(10)area_calc(20) 介绍了在函数调用中使用单个参数。这些参数在每次函数调用时传递给函数定义中的参数 'r',并接受值 10 和 20 来完成任务。

参数大致分为 4 种类型。

  1. 必需参数

    必需参数,也称为位置参数,是在 Python 中向函数传递参数的最简单方法。由于函数调用中的参数与函数定义中的参数相对应,因此应仔细考虑传递参数的数量和位置(顺序)。

    #this is function definition
    def person(name, age, place):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    # this is function call
    person('Chris',17,'USA')
     
    

    输出

    
    Hi,Iam Chris 17 years lives in  USA
    

    在上面的示例中,函数调用 person('Chris',17,'USA') 有 3 个参数,函数定义 person(name,age,place) 有 3 个参数。在这里,函数定义中的参数充当变量,用于保存函数调用的值。这些参数在函数局部定义,当函数被调用时,参数会按照它们的位置顺序传递给参数。因此称为位置参数。

    下面的可视化图表清晰地展示了这个概念。

    Python Function - Required Arguments

    注意:传递的参数顺序必须与函数中参数的顺序相对应。

    如果你传递的位置参数顺序不对,会发生什么?显然,函数会照常执行,但结果可能不是你期望的。例如,person('USA',17,'Chris') 会产生结果“Hi, Iam USA 17 years old lives in Chris”,这不是预期的结果。

    在考虑要传递的参数数量时,与顺序一样,参数的数量应该与函数中的参数数量相匹配。下面的例子解释了为什么这个参数被称为必需参数。

    示例:多一个参数

    
    def person(name, age, place):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    person('Chris','Jake',17,'USA',)
     
    

    输出

    
    person('Chris','Jake',17,'USA',)
    TypeError: person() takes 3 positional arguments 
    but 4 were given
    
    

    示例:缺少一个参数

    
    def person(name, age, place):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    person('Chris',17)
     
    

    输出

    
    person('Chris',17)
    TypeError: person() missing 1 required positional argument: 'place'
    

    这里的两个例子表明,传递给函数的参数数量必须与函数定义中的参数数量相匹配。如果我们增加或减少一个参数,结果将会是错误。

    简而言之,当一个函数被调用时,Python 中的必需参数或位置参数必须指定要传递的适当数量的参数,并且顺序必须与函数定义中的参数顺序完全相同。

    注意:传递的参数数量必须与函数中的参数数量相匹配。

  2. 关键字参数

    引入 Python 中的关键字参数是为了放宽对必需参数的一些限制。关键字参数的形式为=,当我们调用一个函数时。这里的每个关键字都必须与函数定义中的一个参数相对应。让我们看看如何用关键字参数修改前面的例子。

    示例:说明 Python 中关键字参数的用法

    
    #this is function definition
    def person(name, age, place):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    # this is function call
    person(name='Chris',age=17,place ='USA')
    person(age=17,place ='USA',name='Chris')
     
    

    输出

    
    Hi ,Iam Chris 17 years old lives in  USA
    Hi ,Iam Chris 17 years old lives in  USA
    

    在上面的示例中,您会注意到高亮显示的函数调用中的参数顺序是乱的。但它仍然输出了正确的答案。这表明当在函数调用中指定关键字参数时,顺序无关紧要,这意味着调用函数通过名称识别分配给参数的相应参数。

    示例:关键字引用未声明的参数

    
    def person(name, age, place):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    person(name='Chris',age=17,country ='USA')
     
    

    输出

    
    person(name='Chris',age=17,country ='USA')
    TypeError: person() got an unexpected keyword argument 'country'
    

    该示例显示了当关键字引用函数中未声明的参数时会发生什么。它会产生一个异常。因此,为参数和关键字使用相同的名称至关重要。

    关键字参数只在要传递的参数顺序上提供了便利,但在要传递的参数数量上没有。当函数调用中的参数数量与参数数量不匹配时,会产生异常,就像位置参数一样。

  3. 默认参数

    默认参数,顾名思义,为函数参数提供一个默认值,以应对函数调用期间缺少参数值的情况。默认参数在函数定义中定义,其中参数的形式为=,其中是该参数的默认值。以下示例阐明了默认参数的概念

    
    #this is function definition
    def person(name='Tom', age=20, place ='UK'):
     print(' Hi ,Iam',name ,age,'years old lives in ',place)
    
    # this is function call
    person('Chris',17,'USA')
    person('Chris')
     
    

    输出

    
    Hi ,Iam Chris 17 years old lives in  USA
     Hi ,Iam Chris 20 years old lives in  UK
    

    在此示例中

    由此我们可以推断,默认参数通过允许在函数调用期间省略参数,解除了对参数数量的限制。

    • 在函数调用 person('Chris',17,'USA') 期间,所有参数值都被传递给函数参数,因此它产生结果“ Hi ,Iam Chris 17 years old lives in USA”。

    • 第二次函数调用 person('Chris') 只向函数传递了一个参数值,缺少另外两个参数值。即便如此,它还是通过使用函数中为参数设置的默认值,生成了结果“Hi ,Iam Chris 20 years old lives in UK”。

  4. 任意参数/可变长度参数

    Python 允许在函数定义中使用可变长度参数(任意参数),以处理我们不太确定函数需要多少参数的情况。根据参数的类型,它分为两种:

    • 非关键字任意参数

      任意参数通常通过在参数前放置一个 (*) 星号来定义,例如 *args。*args 也称为非关键字任意参数。

      每当参数前缀为星号时,它表示参数的元组打包。函数调用中的参数被打包成一个元组,函数通过其参数名引用该元组。下图是参数元组打包的可视化。tags 是函数定义中的参数,arg1, arg2, arg3, ..., argn 是函数调用期间传递的参数。

      Python Non keyword arbitrary arguments

      下面显示了一个带有可变长度参数的函数定义示例

      
      def fn(*names):
       print(names ,' belongs to',type(names) )
       for i in names:
        print(i)
      
      fn('Red','Green','Blue')
      print('\n')
      fn('Bike','Car','Bus','Train')
       
      

      输出

      
      ('Red', 'Green', 'Blue')  belongs to 
      Red
      Green
      Blue
      
      ('Bike', 'Car', 'Bus', 'Train')  belongs to 
      Bike
      Car
      Bus
      Train
      

      在上述示例中

      • *names 是任意参数,它在每次函数调用期间接受任意长度的参数。
      • fn('Red','Green','Blue') 和 fn('Bike','Car','Bus','Train') 是两个函数调用,分别有 3 个和 4 个参数。这些参数在传递给函数之前被存储为元组,函数内部的 for 循环检索每个参数并产生结果。
    • 关键字任意参数 (**kwargs)

      现在我们已经了解了 *args 是什么以及它的用途,让我们来看看 python 函数中的 **kwargs 是什么以及它的用途。

      **kwargs 用于向函数传递关键字参数。**kwargs 的工作方式与 *args 相同,但它接受的是关键字参数而不是位置参数。函数通过在参数前加上双星号(**)来表示使用关键字任意参数。**星号表示以键值对形式对参数进行字典打包。

      下面给出了一个展示 **kwargs 工作原理的例子

      
      # **Kwargs example
      def fn(**names):
       print(names ,' belongs to',type(names) )
       for key, value in names.items():
        print("{} = {}".format(key,value))
      
      fn(Colour_1='Red',Colour_2= 'Green', Colour_3 ='Blue')
      fn(Vehicle_1= 'Bike',Vehicle_2 ='Car',Vehicle_3='Bus',Vehicle_4 ='Train')
      
       
      

      输出

      
      {'Colour_1': 'Red', 'Colour_2': 'Green', 'Colour_3': 'Blue'}  belongs to 
      Colour_1 = Red
      Colour_2 = Green
      Colour_3 = Blue
      
      {'Vehicle_1': 'Bike', 'Vehicle_2': 'Car', 'Vehicle_3': 'Bus', 'Vehicle_4': 'Train'}  belongs to 
      Vehicle_1 = Bike
      Vehicle_2 = Car
      Vehicle_3 = Bus
      Vehicle_4 = Train
      

      在这个例子中,我们向名为 fn(**names) 的函数调用了两个任意长度的函数,其中 **names 是关键字参数。** names 接受键值对形式的关键字,即作为字典。函数内部的 'for loop' 检索每个项目并产生结果。

Return 语句

return 语句的语法是


return (< [removed]s) >) 
 

Python 函数中的 return 语句是一个可选语句,它有两个明确的目的

  1. return 语句迅速退出函数并将控制权交还给调用者。
  2. return 语句可以有选择地将一些表达式或值传递给调用者。

函数在两种情况下会传递一个 None 对象

  • 当它找到一个没有参数的 return 语句时
  • 当函数中没有提及 return 语句本身时。

以下示例说明了在函数中使用 return 语句


def area_calc(x,y):
 return(x*y)


a = area_calc(10,15)
print('Area is :',a)

 

输出


Area is : 150

什么是匿名函数

Python 中的匿名函数是没有名称的函数。匿名函数使用 Lambda 关键字定义。因此,匿名函数在 Python 中也称为 Lambda 函数。

匿名函数的语法是


lambda arg(s) : expression
 

匿名函数可以接受任意数量的参数,但必须只有一个表达式。它们不能接受多个表达式和命令。Lambda 函数在需要函数对象的地方非常有用。

例如,让我们将前面的示例更改为 lambda 函数的形式;


area_calc =lambda x ,y : x*y

print('Area is ',area_calc(10,20))

 

输出


Area is  200

在此示例中:

  • lambda x ,y : x*y 是 lambda 函数
  • x 和 y 是 lambda 函数的参数
  • x*y 是表达式
     

表达式被求值,其值作为函数对象返回,并赋给标识符 area_calc。现在,匿名函数变成了一个普通函数。

函数中变量的作用域

变量的作用域是学习编程语言时需要解决的最重要的话题之一。变量的作用域指定了变量在函数、类或程序中的访问权限。根据变量的作用域和生命周期,Python 将变量分为两种类型

  1. 全局变量 - 全局变量是在函数外部和全局作用域中声明的变量。具体来说,全局变量可以在函数内部和函数外部访问。该变量在整个程序中都有效。
  2. 局部变量 - 另一方面,局部变量在函数内部和局部作用域中声明。更准确地说,我们可以说局部变量的可访问性仅限于局部函数,并且不能在函数外部访问。

以下示例说明了函数中变量的作用域


a = 0  # a is the global variable
def area_calc(x,y):  # x and y are local variables
 a=x*y
 print('Area is ',a)  # inside function

area_calc(10,20)
print('Area is ',a)  #outside function
print (x*y)        #outputs error as x and y are declared inside function
 

输出


Area is  200
Area is 0

print (x*y)
NameError: name 'x' is not defined

Python 递归

递归是函数调用自身的过程。如果一个函数调用自身,那么这个函数就被称为递归函数,这样的调用被称为递归调用。更具体地说,一个函数会重复调用自己,直到达到基本情况。递归的常见结构有两个组成部分:

  • 基本情况:递归函数中停止递归的最终情况。
  • 递归情况:进行递归调用的情况

以下程序演示了在 Python 中使用递归来求一个数的阶乘。在看程序之前,让我们回顾一下如何求 5 的阶乘。

求阶乘的通用方法 示例:5!
n! = n x (n-1)! 5! = 5 x 4!
n! = n x (n-1) x (n-2)! 5! = 5 x 4 x 3!
n! = n x (n-1) x (n-2) x (n-3)! 5! = 5 x 4 x 3 x 2!
  5! = 5 x 4 x 3 x 2 x 1!
n! = n x (n-1) x (n-2) x (n-3) ….3! 5! = 5 x 4 x 3 x 2 x 1 => 120
n! = n x (n-1) x (n-2) x (n-3) ….3 x 2!  
n! = n x (n-1) x (n-2) x (n-3) ….3 x 2 x 1!  

求阶乘的通用方法

从上表我们了解到,一个大问题被分解成相同问题的较小块,并重复这个过程,直到我们达到一个基本情况。在这个例子中,1! 是基本情况,值为 1。