本章介绍了函数的基本概念和使用方法,包括定义函数、传递参数、局部变量、全局变量、默认参数、关键字参数、返回值和文档字符串。
掌握这些概念对于编写结构化和可维护的Python代码至关重要。
定义函数
-
使用
def
关键字
定义函数始于def
关键字,它告诉Python接下来是一个函数定义。
-
函数名
def
关键字之后是函数名,它应该清晰地反映函数的功能。函数名遵循与变量相同的命名规则:必须以字母或下划线开头,不能使用Python的保留字,并且是大小写敏感的。
-
圆括号和参数
函数名后面跟着一对圆括号,其中包含零个或多个参数。参数是传递给函数的值,它们允许函数具有灵活性和通用性。
-
参数列表
- 必需参数:在圆括号中按顺序列出,函数调用时必须提供。
- 关键字参数:使用
=
后跟默认值定义,如果函数调用时没有提供相应的实参,将使用默认值。 - 可变参数列表:使用
*
(用于非关键字参数)或**
(用于关键字参数)定义,允许函数接受任意数量的额外参数。
-
函数体
函数的定义以冒号(:
)结束,后跟一个缩进的代码块,这是函数体。函数体中的代码定义了函数执行的操作。
-
返回值
使用return
语句从函数返回值。当return
语句执行时,函数将立即结束,并返回指定的值给调用者。如果函数没有返回值,return
可以不带任何表达式,或者根本不写return
语句(在这种情况下,函数默认返回None
)。
-
示例
下面是一个简单的函数定义示例,该函数接受两个参数,计算它们的和,并返回结果:
def add_numbers(a, b): """ 计算并返回两个数字的和。 参数: a (int/float): 第一个数字。 b (int/float): 第二个数字。 返回: int/float: 两个数字的和。 """ result = a + b return result
# 调用函数
sum = add_numbers(3, 5)
print("两个数的和是:", sum) # 输出: 两个数的和是: 8
在这个例子中,add_numbers
是一个函数名,它接受两个参数a
和b
。函数体只有一行代码,计算a
和b
的和,并将结果存储在变量result
中。然后,使用return
语句将结果返回给调用者。
函数定义是Python编程中的基础概念之一,它使得代码更加模块化、可重用和易于维护。通过定义函数,你可以创建复杂的程序结构,并将任务分解为更小、更易于管理的部分。
使用函数形参
- 形参(formal parameters)是在函数定义中指定的变量,用于接收函数调用时传入的值(实参)。
- 函数调用时,实参的顺序必须与形参的顺序相匹配。
局部变量
- 在函数内部声明的变量是局部变量,它们的作用域仅限于函数内部。
- 改变局部变量的值不会影响全局变量(除非使用
global
关键字)。
使用global
语句
-
何时使用
global
语句
-
当你想要在函数内部修改一个全局变量的值时。
- 当你想要在函数内部创建一个新的全局变量时(不推荐,因为这可能会导致命名冲突和代码难以理解)。
- 当你想要确保函数内部使用的变量是全局作用域中的变量,而不是在函数内部新定义的局部变量时。
-
如何使用
global
语句
global
语句通常位于函数体内部,它告诉Python解释器后续声明的变量是全局变量。以下是 使用global
语句的基本语法:
def my_function(): global global_variable global_variable = "我是全局变量" # 其他代码...
# 函数外部定义全局变量
global_variable = "原始全局变量值"
# 调用函数 my_function()
# 打印全局变量的值,以验证它已被函数修改
print(global_variable) # 输出: 我是全局变量
在这个例子中,global
语句在函数my_function
内部声明了global_variable
为全局变量。这意味着当函数内部对global_variable
进行赋值操作时,它实际上是在修改全局作用域中的变量,而不是在函数内部创建一个新的局部变量。
-
注意事项
- 过度使用
global
语句可能会导致代码难以理解和维护,因为它破坏了函数的封装性和局部性。 - 在函数内部尽量避免修改全局变量,这可能会导致代码中的bug更难发现和修复。
- 在同一个函数中,如果你需要声明多个全局变量,可以在
global
语句后面列出所有这些变量的名字,用空格分隔,例如:global var1, var2, var3
。 - 在Python 3中,如果你想要修改一个全局变量,除了使用
global
语句外,还可以使用nonlocal
语句来声明一个变量为嵌套作用域中的变量(当函数内部有多层嵌套作用域时使用)。
默认参数值
在Python中,函数默认参数值是一个非常方便的特性,它允许在定义函数时为参数指定默认值。这意味着在调用函数时,如果没有为这些参数提供值,Python将自动使用它们的默认值。通过使用默认参数值,你可以编写出更加灵活和用户友好的函数,使它们更容易被调用和重用。
-
定义带有默认参数值的函数
当你定义一个函数时,可以在参数列表中为参数赋予默认值。这通过在参数名后面直接指定一个等号和默认值来实现。例如:
def greet(name, greeting='Hello'): print(greeting, name)
在这个例子中,greet
函数有两个参数:name
和greeting
。greeting
参数的默认值是'Hello'
。当你调用greet
函数时,如果没有提供greeting
参数,它将自动使用'Hello'
作为默认值。
-
调用带有默认参数值的函数
调用带有默认参数值的函数时,可以省略具有默认值的参数:
greet('Alice') # 输出: Hello Alice greet('Bob', 'Good morning') # 输出: Good morning Bob
在第一个调用中,我们只提供了name
参数的值,greeting
参数使用了默认值'Hello'
。在第二个调用中,我们提供了name
和greeting
两个参数的值,所以greeting
参数的值被覆盖为'Good morning'
。
-
注意事项
-
默认参数值在函数定义时被计算一次,并在函数的整个生命周期内保持不变。这意味着如果你将可变对象(如列表或字典)作为默认值,那么所有调用该函数的实例都将共享同一个对象。例如:
def func(a, b=None):b = b or areturn a + bprint(func(1)) # 输出: 2,因为b是None,所以返回1+1 print(func(1, 2)) # 输出: 3
在这个例子中,
b
被初始化为None
,然后使用or
运算符赋值为a
的值。这意味着每次调用func(1)
时,都会返回2
,因为b
被设置为1
。 -
从Python 3开始,不建议使用可变对象作为默认参数值,因为这可能导致意外的行为。如果你需要一个默认的可变对象,最好在函数内部创建一个新的对象实例。
-
默认参数值应该用于那些你希望在大多数情况下保持不变的值,而不是用于那些可能会频繁变化的值。
关键字参数(命名参数)
在Python中,关键字参数(也称为命名参数)允许你在调用函数时明确指定参数的名称和值。这种语法提供了一种清晰的方式来传递参数,尤其是当函数有很多参数时,它可以使得代码更易读和更易于维护。关键字参数是Python中一个非常有用的功能,它提高了函数的可读性和灵活性。通过使用关键字参数,你可以编写出更加清晰和易于维护的代码。
-
基本语法
当你定义一个函数时,你可以使用关键字参数来指定参数的名称和默认值。在调用函数时,你可以通过在参数值前加上参数名和等号来明确地传递每个参数:
def func(a, b, c=0): return a + b + c
# 使用关键字参数调用函数
result = func(a=1, b=2, c=3)
在这个例子中,func
函数有三个参数:a
、b
和c
。c
是一个具有默认值0
的关键字参数。在调用func
时,我们使用了关键字参数来指定每个参数的值。
-
优点
- 清晰性:关键字参数使得函数调用更易于理解,因为参数的用途在调用时就被明确了。
- 灵活性:你可以只传递具有默认值的参数,或者按需传递任意数量的参数。
- 顺序无关性:使用关键字参数调用函数时,不需要按照函数定义中的参数顺序。
-
与位置参数结合使用
关键字参数可以与位置参数结合使用,但必须在位置参数之后:
def func(first, second, third='third'): return first + second + third
# 混合使用位置参数和关键字参数
result = func(1, second=2, third='other third')
在这个例子中,我们首先通过位置传递了first
参数的值1
,然后使用关键字参数传递了second
和third
的值。
-
注意事项
- 确保在使用关键字参数时,所有必需的位置参数都已经提供了值,否则你会遇到
TypeError
。 - 如果函数定义中使用了
*args
或**kwargs
,那么所有的关键字参数都应该放在*args
或**kwargs
之后。 - 在文档字符串(DocString)中明确指出哪些参数是必需的,哪些有默认值,以及它们的含义,这有助于其他开发者理解和使用你的函数。
可变参数列表
在Python中,可变参数列表允许函数接受任意数量的位置参数或关键字参数,提供了极大的灵活性。这在你需要创建一个可以接受多种参数组合的函数时特别有用。以下是两种主要的可变参数列表:
-
非关键字可变参数(*args)
使用*
符号定义非关键字可变参数,通常称为args
。这允许函数接受任意数量的位置参数,并将它们作为一个元组处理。
def my_function(*args): for arg in args: print(arg)
调用这个函数时,可以传递任意数量的参数:
my_function(1, 2, 3, 'a', 'b')
在这个例子中,args
是一个元组,包含了所有传递给my_function
的参数。
-
关键字可变参数(**kwargs)
使用**
符号定义关键字可变参数,通常称为kwargs
。这允许函数接受任意数量的关键字参数,并将它们作为一个字典处理。
def my_function(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
调用这个函数时,可以传递任意数量的关键字参数:
my_function(name='Alice', age=25, city='Wonderland')
在这个例子中,kwargs
是一个字典,包含了所有传递给my_function
的关键字参数。
-
同时使用两种可变参数
你可以在同一个函数定义中同时使用*args
和**kwargs
,但*args
必须在**kwargs
之前:
def my_function(*args, **kwargs): print("Positional arguments:", args) print("Keyword arguments:", kwargs)
my_function(1, 2, 'a', name='Alice', age=25)
在这个例子中,args
将接收所有位置参数,而kwargs
将接收所有关键字参数。
-
注意事项
- 当使用可变参数列表时,函数内部的参数列表中出现的普通参数(非可变参数列表)必须在可变参数列表之前定义。
- 如果你使用
*args
,那么所有跟随其后的位置参数都将被视为可变参数列表的一部分。 - 类似地,如果你使用
**kwargs
,那么所有跟随其后的关键字参数都将被视为关键字可变参数列表的一部分。 - 可变参数列表使得函数调用更加灵活,但也可能导致函数的签名不够明确,因此在设计函数时应当谨慎使用。
通过使用可变参数列表,你可以创建更加通用和灵活的函数,以适应各种不同的调用场景。
return
语句
return
语句用于从函数中返回一个值给调用者。- 如果函数没有返回值,
return
可以不带任何值。 - 没有
return
语句的函数默认返回None
。
使用DocStrings
DocStrings(文档字符串)是Python中用于记录函数、类、模块等元素的文档信息的一种约定。它们通常位于被记录元素的直接下方,并被三引号(单引号'''
或双引号"""
)包围。DocStrings提供了一种标准的方式来嵌入文档到Python代码中,这些文档可以通过内置的__doc__
属性来访问。
-
基本语法
DocStrings的基本语法是在三引号内编写文本,可以包含多行文本:
def my_function(): """ 这是一个文档字符串的例子。 这里可以包含多行文本,用于描述函数的功能、参数、返回值等。 """ pass
-
内容约定
- 首行:通常是最重要的一行,应该简洁地描述函数或类的作用。
- 后续行:提供更详细的描述,包括参数的说明、函数的副作用、返回值的描述等。
- 格式:推荐使用reStructuredText(reST)格式,这是一种用于文档的轻量级标记语言。
-
访问DocStrings
你可以通过__doc__
属性来访问任何对象的DocString:
print(my_function.__doc__)
-
使用DocStrings的最佳实践
- 始终使用:即使是简单的函数或类,也应该有一个DocString来描述它们的基本功能。
- 保持更新:随着代码的变化,确保DocStrings也同步更新,以保持信息的准确性。
- 清晰的描述:DocStrings应该清晰、准确地描述元素的功能和用法。
- 参数和返回值:如果函数有参数或返回值,应该在DocString中详细说明。
- 例子:如果适用,提供一个使用函数的简短示例可以增加文档的可读性。
-
示例
下面是一个包含DocString的函数示例,以及如何访问和打印它的DocString:
def greet(name, greeting='Hello'): """ 打印问候语。 参数: name (str): 要问候的人的名字。 greeting (str): 问候语的开始部分,默认为 'Hello'。 返回: str: 完整的问候语字符串。 """ return f"{greeting}, {name}!" # 访问并打印函数的DocString
print(greet.__doc__)
# 调用函数并打印结果
print(greet('Alice')) # 输出: Hello, Alice!
在这个例子中,greet
函数的DocString详细描述了函数的作用、参数和返回值。通过打印greet.__doc__
,我们可以看到完整的文档字符串。
DocStrings是Python文档化的一个重要部分,它们使得代码更加自解释,有助于其他开发者理解和使用你的代码。