摘要:在本节中,你将学习如何使用 def
关键字开发 Python 函数。
函数是一个命名的代码块,用于执行任务或返回值。
有时,你需要在程序中多次执行某个任务。但你不想在多个地方重复复制相同的代码。
为此,你可以将代码封装在一个函数中,并在需要时调用此函数来执行任务。
例如,每当你想在屏幕上显示一个值时,都需要调用 print()
函数。在幕后,Python 会运行 print()
函数内部的代码以在屏幕上显示一个值。
在实践中,你可以使用函数将大型程序分解为更小、更易于管理的部分。这些函数将使你的程序更易于开发、阅读、测试和维护。
print()
函数是 Python 中众多内置函数之一。这意味着这些函数在程序的任何地方都可以使用。
在本节中,你将学习如何定义用户自定义的 Python 函数。
以下是一个显示问候语的简单函数:
def greet():
""" Display a greeting to users """
print('Hi')
此示例展示了函数最简单的结构。一个函数有两个主要部分:函数定义和函数体。
函数定义以 def
关键字和函数名(greet
)开头。
如果函数需要一些信息来完成其工作,你需要在括号 ()
内指定这些信息。此示例中的 greet
函数不需要任何信息,因此其括号是空的。
函数定义总是以冒号 :
结尾。
所有缩进的行(紧跟在函数定义之后)构成了函数体。
被三引号包围的文本字符串称为文档字符串(docstring)。它描述了函数的功能。Python 使用文档字符串自动生成函数的文档。
print('Hi')
是函数体中唯一一条实际代码。greet()
函数执行一项任务:打印 'Hi'
。
当你想使用一个函数时,需要调用它。函数调用指示 Python 执行函数内部的代码。
要调用一个函数,你需要写出函数名,并在括号中指定函数所需的信息。
以下示例调用了 greet()
函数。由于 greet()
函数不需要任何信息,因此你需要像这样指定空括号:
greet()
如果你运行程序:
def greet():
""" Display a greeting to users """
print('Hi')
greet()
它将在屏幕上显示一条问候语:
Hi
假设你想通过用户的名字(name
)来问候他们。为此,你需要在函数定义的括号中指定一个名字,如下所示:
def greet(name):
这个name
被称为函数参数(function parameter),或者简称为参数。
当你向函数定义中添加一个参数时,你可以在函数体中将其用作一个变量:
def greet(name):
print(f"Hi {name}")
你只能在 greet()
函数的函数体内访问 name
参数,而不是在函数体外。
当你调用带有参数的函数时,需要传递信息。例如:
greet('John')
以下是完整的程序:
def greet(name):
print(f"Hi {name}")
greet('John')
输出:
Hi John
你传递给函数的值称为参数(argument)。在此示例中,'John'
就是一个参数。
或者,你也可以通过传递一个变量来调用该函数:
def greet(name):
print(f"Hi {name}")
first_name = 'Jane'
greet(first_name)
输出:
Hi Jane
在这个示例中,first_name
变量也是 greet()
函数的参数(argument)。
有时,参数(parameter,形参)和参数值(argument,实参)会互换使用。但区分函数的参数和参数值是很重要的。
参数(形参)是函数所需的信息。你在函数定义中指定参数。例如,greet()
函数有一个名为 name
的参数。
参数值(实参)是你传递给函数的数据。例如,文本字符串 'John'
或变量 jane
是函数的参数值(实参)。
函数可以像 greet()
函数那样执行任务,也可以返回一个值。函数返回的值称为返回值加粗样式。
要从函数中返回值,你需要在函数体中使用 return
语句。
return value
以下示例修改了 greet()
函数,使其返回一条问候语,而不是在屏幕上显示它:
def greet(name):
return f"Hi {name}"
当你调用 greet()
函数时,可以将其返回值赋给一个变量:
greeting = greet('John')
然后在屏幕上显示它:
print(greeting)
新的 greet()
函数比旧的好,因为它不依赖于 print()
函数。
之后,你可以在其他应用程序中重用 greet()
函数。例如,你可以在 Web 应用程序中使用它,在用户登录后向他们问候。
def greet(name):
return f"Hi {name}"
greeting = greet('John')
print(greeting)
输出:
Hi John
一个函数可以有零个、一个或多个参数。
以下示例定义了一个名为 sum()
的函数,该函数用于计算两个数的和:
def sum(a, b):
return a + b
total = sum(10,20)
print(total)
输出:
30
在这个示例中,sum()
函数有两个参数 a
和 b
,并返回它们的和。
当函数有多个参数时,你需要使用逗号将它们分隔开。
当你调用函数时,需要传递所有的参数值(实参)。如果你向函数传递了过多或过少的参数值(实参),就会得到一个错误。
在以下函数调用中,在函数体内 a
将是 10,b
将是 20:
total = sum(10, 20)
总结
def
关键字来定义一个新函数。函数由函数定义和函数体组成。return
语句从函数中返回值。摘要:在本节中,你将学习 Python 默认参数以简化函数调用。
在定义函数时,你可以为每个参数指定一个默认值。
要为参数指定默认值,请使用以下语法:
def function_name(param1, param2=value2, param3=value3, ...):
在此语法中,你使用赋值运算符 (=
) 为每个参数指定默认值 (value2
, value3
, …)。
当你调用函数并向具有默认值的参数传递参数值(实参)时,函数将使用该参数值(实参)而不是默认值。
然而,如果你不传递该参数值(实参),函数将使用默认值。
要使用默认参数,你需要将具有默认值的参数放在其他参数之后。否则,你将得到语法错误。
例如,你不能这样做:
def function_name(param1=value1, param2, param3):
这将导致语法错误。
以下示例定义了一个返回问候消息的 greet()
函数:
def greet(name, message='Hi'):
return f"{message} {name}"
greet()
函数有两个参数:name
和 message
。其中,message
参数具有默认值 'Hi'
。
以下代码调用了 greet()
函数并传递了两个参数值(实参):
def greet(name, message='Hi'):
return f"{message} {name}"
greeting = greet('John', 'Hello')
print(greeting)
输出:
Hello John
由于我们向 greet()
函数传递了第二个参数值(实参),因此它使用了该参数值而不是默认值。
以下示例调用 greet()
函数时未传递第二个参数值(实参):
def greet(name, message='Hi'):
return f"{message} {name}"
greeting = greet('John')
print(greeting) # 打印 greeting 的值
输出:
Hi John
在这种情况下,greet()
函数使用了 message
参数的默认值。
以下示例重新定义了 greet()
函数,其中两个参数都具有默认值:
def greet(name='there', message='Hi'):
return f"{message} {name}"
在此示例中,你可以调用 greet()
函数而不传递任何参数:
def greet(name='there', message='Hi'):
return f"{message} {name}"
greeting = greet()
print(greeting)
输出:
Hi there
假设你希望 greet()
函数返回类似“Hello there”
这样的问候语。你可能会想到如下函数调用方式:
def greet(name='there', message='Hi'):
return f"{message} {name}"
greeting = greet('Hello')
print(greeting)
不幸的是,它返回了一个意外的值:
Hi Hello
因为当你传递 'Hello'
参数时,greet()
函数会将其视为第一个参数,而不是第二个参数。
为了解决这个问题,你需要使用关键字参数来调用 greet()
函数,如下所示:
def greet(name='there', message='Hi'):
return f"{message} {name}"
greeting = greet(message='Hello')
print(greeting)
输出:
Hello there
摘要:在本节中,你将学习 Python 关键字参数,以及如何使用它们使函数调用更加清晰明了。
让我们从一个简单的函数开始,该函数根据售价和折扣计算净价:
def get_net_price(price, discount):
return price * (1-discount)
get_net_price()
函数有两个参数:price
(价格)和 discount
(折扣)。
以下展示了如何调用 get_net_price()
函数,以根据价格 100
和折扣 10%
计算净价:
def get_net_price(price, discount):
return price * (1 - discount)
net_price = get_net_price(100, 0.1)
print(f'{net_price: .2f}')
输出:
90.00
在这个示例中,我们使用 f 字符串(f-string
)将输出数字格式化为保留两位小数(f'{net_price: .2f}'
)。
在 get_net_price(100, 0.1)
这个函数调用中,我们是以位置参数的方式传递每个参数的。换句话说,我们先传递了 price
参数,然后传递了 discount
参数。
然而,get_net_price(100, 0.1)
这个函数调用存在可读性问题。因为仅通过查看这个函数调用,你无法知道哪个参数是 price
,哪个参数是 discount
。
除此之外,在调用 get_net_price()
函数时,你需要知道每个参数的位置。
如果你不知道参数的位置,函数将会错误地计算 net_price
。例如:
def get_net_price(price, discount):
return price * (1-discount)
net_price = get_net_price(0.1, 100)
print(f'{net_price: .2f}')
输出:
-9.9
为了提高可读性,Python 引入了关键字参数。
以下是关键字参数的语法:
fn(parameter1=value1, parameter2=value2)
通过使用关键字参数语法,你无需按照函数定义中的顺序指定参数。
因此,你可以像这样交换参数的位置来调用函数:
fn(parameter2=value2, parameter1=value1)
以下展示了如何使用关键字参数语法来调用 get_net_price()
函数:
def get_net_price(price, discount):
return price * (1 - discount)
net_price = get_net_price(
price=100,
discount=0.1
)
print(f'{net_price: .2f}')
或者:
def get_net_price(price, discount):
return price * (1-discount)
net_price = get_net_price(
discount=0.1,
price=100
)
print(f'{net_price: .2f}')
这两种(调用方式)都会返回相同的结果。
在最后一个参数后面可以加一个逗号(尾随逗号):
def get_net_price(price, discount):
return price * (1-discount)
net_price = get_net_price(
discount=0.1,
price=100,
)
print(f'{net_price: .2f}')
当你使用关键字参数时,重要的是它们的名称,而不是它们的位置。
def get_net_price(price, discount):
return price * (1-discount)
net_price = get_net_price(
price=100,
discount=0.1
)
print(net_price)
请注意,你可以通过混合使用位置参数和关键字参数来调用函数。例如:
def get_net_price(price, discount):
return price * (1-discount)
net_price = get_net_price(
100,
discount=0.1
)
print(f'{net_price: .2f}')
假设你有如下的 get_net_price()
函数,它根据售价、税率和折扣来计算净价。
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
在 get_net_price()
函数中,tax
和 discount
参数分别具有 7% 和 5% 的默认值。
以下代码调用了 get_net_price()
函数,并为 tax
和 discount
参数使用了默认值:
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(100)
print(f'{net_price: .2f}')
输出:
101.65
假设你想要为 tax
参数使用默认值,但不为 discount
使用默认值。下面的函数调用不能正确工作。
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(100, 0.06)
print(f'{net_price: .2f}')
输出:
100.70
……因为 Python 会将 100
赋值给 price
,将 0.1
赋值给 tax
,而不是赋值给 discount
。
要解决这个问题,你必须使用关键字参数:
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(
price=100,
discount=0.06
)
print(f'{net_price: .2f}')
输出:
100.58
或者你可以混合使用位置参数和关键字参数:
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(
100,
discount=0.06
)
print(f'{net_price: .2f}')
输出:
100.58
一旦你使用了关键字参数,后续的参数也必须使用关键字参数。
以下代码会导致错误,因为它在关键字参数之后使用了位置参数:
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(
100,
tax=0.08,
0.06
)
print(f'{net_price: .2f}')
错误:
SyntaxError: positional argument follows keyword argument
要解决这个问题,你需要像这样为第三个参数使用关键字参数:
def get_net_price(price, tax_rate=0.07, discount=0.05):
discounted_price = price * (1 - discount)
net_price = discounted_price * (1 + tax_rate)
return net_price
net_price = get_net_price(
100,
tax_rate=0.08,
discount=0.06
)
print(f'{net_price: .2f}')
输出:
101.52
摘要:在本节中,你将了解 Python 递归函数,以及如何使用它们来简化你的代码。
递归函数是一种会不断调用自身,直到满足特定条件才停止调用的函数。
下面的 fn()
函数就是一个递归函数,因为它在函数内部调用了自身:
def fn():
# ...
fn()
# ...
在 fn()
函数中,#...
表示其他代码。
此外,一个递归函数需要有一个停止自身调用的条件。所以你需要添加一个像这样的 if
语句:
def fn():
# ...
if condition:
# stop calling itself
else:
fn()
# ...
通常,你会使用递归函数将一个难以解决的大问题分解成若干个易于解决的小问题。
在编程中,你会经常发现递归函数被应用于诸如树、图和二分查找等数据结构和算法中。
下面我们来看一些使用 Python 递归函数的例子。
假设你需要开发一个倒计时函数,它能从指定的数字开始倒数到零。
例如,如果你调用这个从 3 开始倒计时的函数,它将输出如下内容:
3
2
1
下面定义了 count_down()
函数:
def count_down(start):
""" Count down from a number """
print(start)
如果你现在调用 count_down()
函数:
count_down(3)
……它将只显示数字3。
要显示数字3、2和1,你需要:
count_down(3)
来显示数字3。count_down(2)
来显示数字2。count_down(1)
来显示数字1。为了做到这一点,在 count_down()
函数内部,你需要定义一个逻辑,以参数2和1来调用 count_down()
函数。
要实现这一点,你需要让 count_down()
函数成为递归函数。
下面定义了一个递归的 count_down()
函数,并通过传入数字3来调用它:
def count_down(start):
""" Count down from a number """
print(start)
count_down(start-1)
count_down(3)
如果你执行这个程序,你将会看到以下错误:
RecursionError: maximum recursion depth exceeded while calling a Python object
原因是 count_down()
函数会无限地调用自身,直到系统将其停止。
因为当数字减到零时你需要停止倒计时。要做到这一点,你可以添加一个像这样的条件:
def count_down(start):
""" Count down from a number """
print(start)
# call the count_down if the next
# number is greater than 0
next = start - 1
if next > 0:
count_down(next)
count_down(3)
输出:
3
2
1
在这个例子中,count_down()
函数仅当下一个数字大于零时才会调用自身。换句话说,如果下一个数字是零,它就会停止调用自身。
假设你需要计算一个数列的和,例如从 1 到 100 的和。一个简单的做法是使用 range()
函数配合 for
循环:
def sum(n):
total = 0
for index in range(n+1):
total += index
return total
result = sum(100)
print(result)
输出:
5050
为了运用递归技术,你可以按如下方式计算从 1 到 n 的数列的和:
只要 sum()
函数的参数大于零,它就会不断地调用自身。
下面定义了 sum()
函数的递归版本:
def sum(n):
if n > 0:
return n + sum(n-1)
return 0
result = sum(100)
print(result)
输出:
5050
这个递归函数要短得多,而且可读性更强。
如果你使用三元运算符,sum()
函数会更加简洁:
def sum(n):
return n + sum(n-1) if n > 0 else 0
result = sum(100)
print(result)
输出:
5050
摘要:在本节中,你将了解 Python 的Lambda 表达式,以及如何使用它们来编写匿名函数。
有时候,你需要编写一个只有一个表达式的简单函数。然而,你只需要使用这个函数一次。因此,为了这个目的专门定义该函数就没有必要了。
这就是 PythonLambda 表达式发挥作用的地方。
Python 的Lambda 表达式允许你定义匿名函数。
匿名函数是没有名字的函数。当你只需要使用一次函数时,匿名函数就很有用。
一个Lambda 表达式通常包含一个或多个参数,但它只能有一个表达式。
下面展示了Lambda 表达式的语法:
lambda parameters: expression
它等同于下面这个没有名称(anonymous
意为匿名)的函数:
def anonymous(parameters):
return expression
在 Python 中,你可以将一个函数传递给另一个函数,或者从另一个函数中返回一个函数。
下面定义了一个名为 get_full_name()
的函数,它用于根据名和姓来格式化出完整的姓名:
def get_full_name(first_name, last_name, formatter):
return formatter(first_name, last_name)
get_full_name()
函数接受三个参数:
first_name
)last_name
)formatter
)。反过来,formatter
函数接受两个参数,即名字和姓氏。下面定义了两个函数,它们根据名字和姓氏以不同的格式返回完整的姓名:
def first_last(first_name, last_name):
return f"{first_name} {last_name}"
def last_first(first_name, last_name):
return f"{last_name}, {first_name}"
这向你展示了如何通过传入名字、姓氏以及 first_last
函数或 last_first
函数来调用 get_full_name()
函数:
full_name = get_full_name('John', 'Doe', first_last)
print(full_name) # John Doe
full_name = get_full_name('John', 'Doe', last_first)
print(full_name) # Doe, John
以下是完整代码:
def get_full_name(first_name, last_name, formatter):
return formatter(first_name, last_name)
def first_last(first_name, last_name):
return f"{first_name} {last_name}"
def last_first(first_name, last_name):
return f"{last_name}, {first_name}"
full_name = get_full_name('John', 'Doe', first_last)
print(full_name) # John Doe
full_name = get_full_name('John', 'Doe', last_first)
print(full_name) # Doe, John
输出:
John Doe
Doe, John
你可以使用 lambda 表达式,而不是定义 first_last
和 last_first
这两个函数。
例如,你可以使用下面的 lambda 表达式来表示 first_last
函数:
lambda first_name,last_name: f"{first_name} {last_name}"
这个 lambda 表达式接受两个参数,并按照名字、空格、姓氏的顺序将它们连接成一个格式化的字符串。
并且下面使用一个 lambda 表达式来改写 last_first
函数,该表达式返回的全名格式为:姓氏、空格、名字:
lambda first_name, last_name: f"{last_name} {first_name}"
通过使用 lambda 表达式,你可以按如下方式调用 get_full_name()
函数:
def get_full_name(first_name, last_name, formatter):
return formatter(first_name, last_name)
full_name = get_full_name(
'John',
'Doe',
lambda first_name, last_name: f"{first_name} {last_name}"
)
print(full_name)
full_name = get_full_name(
'John',
'Doe',
lambda first_name, last_name: f"{last_name}, {first_name}"
)
print(full_name)
输出:
John Doe
Doe, John
下面的 times()
函数返回一个函数,该函数是一个 lambda 表达式:
def times(n):
return lambda x: x * n
而这个例子展示了如何调用 times()
函数:
def times(n):
return lambda x: x * n
double = times(2)
由于 times()
函数返回一个函数,所以 double
也是一个函数。要调用它,你需要像这样加上括号:
def times(n):
return lambda x: x * n
double = times(2)
result = double(2)
print(result)
result = double(3)
print(result)
输出:
4
6
下面展示了使用 times()
函数的另一个示例:
def times(n):
return lambda x: x * n
triple = times(3)
print(triple(2)) # 6
print(triple(3)) # 9
观察以下案例:
callables = []
for i in (1, 2, 3):
callables.append(lambda: i)
for f in callables:
print(f())
它的工作原理如下:
callables
的列表。callables
列表中。callables
列表并调用其中的每个函数。预期的输出将会是:
1
2
3
然而,该程序显示了以下输出:
3
3
3
问题在于,这三个 lambda 表达式都引用了变量 i
,而不是 i
的当前值。当你调用这些 lambda 表达式时,变量 i
的值是 3。
为了解决这个问题,你需要在创建 lambda 表达式时,将变量 i
绑定到每个 lambda 表达式上。一种方法是使用默认参数:
callables = []
for i in (1, 2, 3):
callables.append(lambda a=i: a)
for f in callables:
print(f())
输出:
1
2
3
在这个例子中,变量 a
的值是在创建 lambda 表达式时进行求值的。因此,该程序返回了预期的输出。
摘要:在本节中,你将学习如何使用文档字符串为函数添加文档说明。
help()
函数简介Python 提供了一个名为 help()
的内置函数,它能让你查看一个函数的文档说明。
以下示例展示了 print()
函数的文档说明:
help(print)
输出:
print(...)
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep: string inserted between values, default a space.
end: string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
请注意,你可以使用 help()
函数来显示模块、类、函数和关键字的文档说明。本节仅专注于函数的文档说明。
为了给你的函数编写文档,你可以使用文档字符串。PEP 257 提供了文档字符串的规范。
当函数体中的第一行是一个字符串时,Python 会将其解释为一个文档字符串。例如:
def add(a, b):
"Return the sum of two arguments"
return a + b
并且你可以使用 help()
函数来查找 add()
函数的文档说明:
def add(a, b):
"Return the sum of two arguments"
return a + b
help(add)
输出:
add(a, b)
Return the sum of two arguments
通常情况下,你会使用多行文档字符串:
def add(a, b):
""" Add two arguments
Arguments:
a: an integer
b: an integer
Returns:
The sum of the two arguments
"""
return a + b
help(add)
输出:
add(a, b)
Add the two arguments
Arguments:
a: an integer
b: an integer
Returns:
The sum of the two arguments
Python 将文档字符串存储在函数的 __doc__
属性中。
以下示例展示了如何访问 add()
函数的 __doc__
属性:
def add(a, b):
""" Add two arguments
Arguments:
a: an integer
b: an integer
Returns:
The sum of the two arguments
"""
return a + b
print(add.__doc__)
help()
函数来获取一个函数的文档说明。