Python - 函数



Python 函数是一组有组织的、可重用的代码,用于执行单个相关操作。Functions 为您的应用程序提供更好的模块化和高度的代码重用。

构建 processing logic 的自上而下的方法涉及定义独立可重用函数的块。可以通过传递所需数据(称为参数或参数)从任何其他函数调用 Python 函数。被调用的函数将其结果返回给调用环境。

python functions

Python 函数的类型

Python 提供以下类型的函数 -

类型 描述
内置函数

Python 的标准库包括许多内置函数。Python 的一些内置函数是 print()、int()、len()、sum() 等。这些函数始终可用,因为它们会在启动 Python 解释器后立即加载到计算机的内存中。

内置模块定义的函数

标准库还捆绑了许多模块。每个模块定义一组函数。这些功能并不容易获得。您需要将它们从各自的 modules 导入到内存中。

用户定义的函数

除了内置函数和内置模块中的函数外,您还可以创建自己的函数。这些函数称为用户定义函数。

定义 Python 函数

您可以定义自定义函数以提供所需的功能。以下是在 Python 中定义函数的简单规则 -

  • 功能块以关键字 def 开头,后跟函数名称和括号 ()。
  • 任何输入参数或参数都应放在这些括号内。您还可以在这些括号内定义参数。
  • 函数的第一个语句可以是 optional statement;函数或文档字符串的文档字符串。
  • 每个函数中的代码块都以冒号 (:) 开头,并缩进。
  • 语句 return [expression] 退出函数,可以选择将表达式传回给调用方。没有参数的 return 语句与 return None 相同。

定义 Python 函数的语法


def function_name( parameters ):
	 	"function_docstring"
	 	function_suite
	 	return [expression]

默认情况下,参数具有位置行为,您需要按照定义参数的相同顺序通知它们。

定义函数后,您可以通过从另一个函数或直接从 Python 提示符调用该函数来执行该函数。

定义 Python 函数的示例

下面的示例演示如何定义函数 greetings()。括号为空,因此没有任何参数。这里,第一行是文档字符串,函数块以 return 语句结尾。


def greetings():
	 	"This is docstring of greetings function"
	 	print ("Hello World")
	 	return

调用此函数时,将打印 Hello world 消息。

调用 Python 函数

定义函数仅为其提供名称,指定要包含在函数中的参数并构建代码块。一旦函数的基本结构完成,您就可以使用函数名称本身来调用它。如果函数需要任何参数,则应在括号内传递这些参数。如果函数不需要任何参数,则括号应留空。

调用 Python 函数的示例

以下是调用 printme() 函数的示例 -


# Function definition is here
def printme( str ):
	 	"This prints a passed string into this function"
	 	print (str)
	 	return;

# Now you can call the function
printme("I'm first call to user defined function!")
printme("Again second call to the same function")

执行上述代码时,它会生成以下输出 -

I'm first call to user defined function!
Again second call to the same function

按引用传递与值传递

在 C 和 C++ 等编程语言中,将变量传递给函数的主要方法有两种,即按值调用按引用调用(也称为按引用传递和按值传递)。但是,我们在 Python 中将变量传递给函数的方式与其他方式不同。

  • 按值调用 -在调用时将变量传递给函数时,实际参数的值将复制到表示形式参数的变量中。因此,形式参数中的任何更改都不会反映在实际参数中。这种传递变量的方式称为按值调用。
  • 按引用调用 -以这种方式传递 variable 时,将传递对内存中对象的引用。形式参数和实际参数(调用代码中的变量)都引用同一个对象。因此,形式参数中的任何更改都会反映在实际参数中。
Pass By Reference 与 Value

Python 使用按引用传递机制。由于 Python 中的 variable 是对内存中对象的标签或引用,因此用作实际参数的变量和形式参数实际上都引用内存中的同一对象。我们可以通过在传递之前和之后检查传递的变量的 id() 来验证这一事实。

在以下示例中,我们将检查变量的 id()。


def testfunction(arg):
	 	print ("ID inside the function:", id(arg))

var = "Hello"
print ("ID before passing:", id(var))
testfunction(var)

如果执行上述代码,则会显示传递前和函数内部的 id()。

ID before passing: 1996838294128
ID inside the function: 1996838294128

该行为还取决于传递的对象是可变的还是不可变的。Python 数值对象是不可变的。当传递一个数值对象,然后函数更改形式参数的值时,它实际上会在内存中创建一个新对象,同时保持原始变量不变。

以下示例显示了不可变对象在传递给函数时的行为方式。


def testfunction(arg):
	 	print ("ID inside the function:", id(arg))
	 	arg = arg + 1
	 	print ("new object after increment", arg, id(arg))

var=10
print ("ID before passing:", id(var))
testfunction(var)
print ("value after function call", var)

它将产生以下输出 -

ID before passing: 140719550297160
ID inside the function: 140719550297160
new object after increment 11 140719550297192
value after function call 10

现在让我们将一个可变对象(比如列表或字典)传递给一个函数。它也通过引用传递,因为传递前后 list 的 id() 是相同的。但是,如果我们在函数内部修改列表,它的全局表示也会反映更改。

在这里,我们传递一个列表,附加一个新项目,并查看原始列表对象的内容,我们将发现它已经更改。


def testfunction(arg):
	 	print ("Inside function:",arg)
	 	print ("ID inside the function:", id(arg))
	 	arg=arg.append(100)
	 	
var=[10, 20, 30, 40]
print ("ID before passing:", id(var))
testfunction(var)
print ("list after function call", var)

它将产生以下输出 -

ID before passing: 2716006372544
Inside function: [10, 20, 30, 40]
ID inside the function: 2716006372544
list after function call [10, 20, 30, 40, 100]

Python 函数参数

函数参数是在调用函数时传递给函数的值或变量。函数的行为通常取决于传递给它的参数。

定义函数时,您可以在括号内指定变量列表(称为形式参数)。这些参数充当数据(在调用函数时将传递给函数的数据的占位符)。调用函数时,必须为每个形式参数提供 value。这些称为实际参数。

函数参数

让我们修改 greetings 函数,并添加 name 参数。作为实际参数传递给函数的字符串在函数内成为 name 变量。


def greetings(name):
	 	"This is docstring of greetings function"
	 	print ("Hello {}".format(name))
	 	return
	 	
greetings("Samay")
greetings("Pratima")
greetings("Steven")

此代码将生成以下输出 -

Hello Samay
Hello Pratima
Hello Steven

Python 函数参数的类型

根据定义 Python 函数时参数的声明方式,它们分为以下几类 -

位置参数或必需参数

必需参数是按正确位置顺序传递给函数的参数。在这里,函数调用中的参数数量应与函数定义完全匹配,否则代码会给出语法错误。

在下面的代码中,我们调用函数 printme() 而不带任何参数,否则会产生错误。


# Function definition is here
def printme( str ):
	 	"This prints a passed string into this function"
	 	print (str)
	 	return;

# Now you can call printme function
printme()

执行上述代码时,它会产生以下结果 -

Traceback (most recent call last):
File "test.py", line 11, in <module>
printme();
TypeError: printme() takes exactly 1 argument (0 given)

关键字参数

关键字参数与函数调用相关。在函数调用中使用关键字参数时,调用方通过参数名称标识参数。这允许您跳过参数或不按顺序放置它们,因为 Python 解释器能够使用提供的关键字将值与参数匹配。

示例 1

以下示例演示如何在 Python 中使用关键字参数。


# Function definition is here
def printme( str ):
	 	"This prints a passed string into this function"
	 	print (str)
	 	return;

# Now you can call printme function
printme( str = "My string")

执行上述代码时,它会产生以下结果 -

My string

示例 2

下面的示例给出了更清晰的画面。请注意,参数的顺序无关紧要。


# Function definition is here
def printinfo( name, age ):
	 	"This prints a passed info into this function"
	 	print ("Name: ", name)
	 	print ("Age ", age)
	 	return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )

执行上述代码时,它会产生以下结果 -

Name: miki
Age 50

默认参数

default 参数是一个参数,如果在函数调用中未为该参数提供值,则假定该参数为默认值。

下面的示例给出了 default 参数的想法,如果未传递,它会打印 default age -


# Function definition is here
def printinfo( name, age = 35 ):
	 	"This prints a passed info into this function"
	 	print ("Name: ", name)
	 	print ("Age ", age)
	 	return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )
printinfo( name="miki" )

执行上述代码时,它会产生以下结果 -

Name: miki
Age 50
Name: miki
Age 35

仅位置参数

那些只能由它们在函数调用中的位置指定的参数称为 Positional-only 参数。它们是通过在函数的参数列表中将所有仅位置参数后放置 “/” 来定义的。此功能是在 Python 3.8 版本中引入的。

使用此类参数的好处是,它可以确保以正确的顺序使用正确的参数调用函数。仅位置参数应作为位置参数而不是关键字参数传递给函数。

在下面的示例中,我们定义了两个仅位置参数,即 “x” 和 “y”。应按照声明参数的顺序使用位置参数调用此方法,否则,我们将得到错误。


def posFun(x, y, /, z):
	 	 print(x + y + z)

print("Evaluating positional-only arguments: ")
posFun(33, 22, z=11)	

它将产生以下输出 -

Evaluating positional-only arguments:
66

仅关键字参数

在调用函数时必须由其名称指定的那些参数称为 Keyword-only 参数。它们是通过在函数的参数列表中将星号 (“*”) 放在任何仅关键字参数之前来定义的。这种类型的参数只能作为关键字参数传递给函数,而不能作为位置参数传递给函数。

在下面的代码中,我们定义了一个具有三个仅关键字参数的函数。要调用这个方法,我们需要传递 keyword 参数,否则会遇到错误。


def posFun(*, num1, num2, num3):
	 	 print(num1 * num2 * num3)

print("Evaluating keyword-only arguments: ")
posFun(num1=6, num2=8, num3=5)	

它将产生以下输出 -

Evaluating keyword-only arguments:
240

任意或可变长度参数

您可能需要处理比定义函数时指定的参数更多的函数。这些参数称为可变长度参数,与 required 和 default 参数不同,它们未在函数定义中命名。

具有非关键字变量参数的函数的语法是这样的 -


def functionname([formal_args,] *var_args_tuple ):
	 	"function_docstring"
	 	function_suite
	 	return [expression]

星号 (*) 位于保存所有非关键字变量参数值的变量名称之前。如果在函数调用期间未指定其他参数,则此 Tuples 将保持为空。

以下是 Python 可变长度参数的简单示例。


# Function definition is here
def printinfo( arg1, *vartuple ):
	 	"This prints a variable passed arguments"
	 	print ("Output is: ")
	 	print (arg1)
	 	for var in vartuple:
	 	 	 print (var)
	 	return;

# Now you can call printinfo function
printinfo( 10 )
printinfo( 70, 60, 50 )

执行上述代码时,它会产生以下结果 -

Output is:
10
Output is:
70
60
50

在接下来的几章中,我们将详细讨论这些函数参数。

Python 函数参数的顺序

函数可以具有上面定义的任何类型的参数。但是,必须按以下顺序声明参数 -

  • 参数列表以仅位置 args 开头,后跟斜杠 (/) 符号。
  • 它后面是常规的位置参数,这些参数可能会也可能不会作为关键字参数调用。
  • 然后可能有一个或多个具有默认值的 args。
  • 接下来,由前缀为单个星号的变量表示的任意位置参数,该变量被视为元组。这是下一个。
  • 如果函数具有任何仅关键字参数,请在其名称开始前加上星号。某些仅关键字参数可能具有默认值。
  • 括号中的最后一个是带有两个星号 ** 的参数,用于接受任意数量的关键字参数。

下图显示了形式参数的顺序 -

形式参数的顺序

返回值的 Python 函数

return 关键字作为函数定义中的最后一条语句,表示函数块结束,程序流返回到调用函数。尽管块中最后一个语句之后的减少缩进也意味着 return,但使用显式 return 是一种很好的做法。

除了流控制之外,该函数还可以将表达式的值返回给调用函数。返回的 expression 的值可以存储在变量中以供进一步处理。

我们来定义 add() 函数。它将传递给它的两个值相加并返回加法。返回的值存储在名为 result 的变量中。


def add(x,y):
	 	z=x+y
	 	return z
a=10
b=20
result = add(a,b)
print ("a = {} b = {} a+b = {}".format(a, b, result))

它将产生以下输出 -

a = 10 b = 20 a+b = 30

匿名函数

当函数未使用 def 关键字以标准方式声明时,这些函数将调用匿名。相反,它们是使用 lambda 关键字定义的。

  • Lambda 表单可以接受任意数量的参数,但只以表达式的形式返回一个值。它们不能包含命令或多个表达式。
  • 匿名函数不能直接调用 print,因为 lambda 需要一个表达式
  • Lambda 函数具有自己的本地命名空间,并且无法访问其参数列表中的变量和全局命名空间中的变量以外的变量。
  • 尽管 lambda 似乎是函数的单行版本,但它们并不等同于 C 或 C++ 中的内联语句,后者的目的是出于性能原因在调用期间传递函数堆栈分配。

语法

lambda 函数的语法仅包含一条语句,如下所示 -


lambda [arg1 [,arg2,.....argn]]:expression

以下示例显示了 lambda 函数形式的工作原理 -


# Function definition is here
sum = lambda arg1, arg2: arg1 + arg2;

# Now you can call sum as a function
print ("Value of total : ", sum( 10, 20 ))
print ("Value of total : ", sum( 20, 20 ))

执行上述代码时,它会产生以下结果 -

Value of total : 30
Value of total : 40

变量范围

程序中的所有变量可能无法在该程序中的所有位置访问。这取决于您声明变量的位置。

变量的范围决定了您可以访问特定标识符的程序部分。Python 中的变量有两个基本范围 -

  • 全局变量
  • 局部变量

全局变量与局部变量

在函数体内部定义的变量具有局部范围,而在函数体外定义的变量具有全局范围。

这意味着局部变量只能在声明它们的函数内部访问,而全局变量可以由所有函数在整个程序体中访问。当你调用一个函数时,其中声明的变量将被引入范围。

以下是本地和全局范围的简单示例 -


total = 0; # This is global variable.
# Function definition is here
def sum( arg1, arg2 ):
	 	# Add both the parameters and return them."
	 	total = arg1 + arg2; # Here total is local variable.
	 	print ("Inside the function local total : ", total)
	 	return total;

# Now you can call sum function
sum( 10, 20 );
print ("Outside the function global total : ", total)	

执行上述代码时,它会产生以下结果 -

Inside the function local total : 30
Outside the function global total : 0