返回值

函数并不总是必须直接显示其输出。 相反,它可以处理一些数据,然后返回一个值或一组值。 函数返回的值称为返回值。 return 语句从函数内部获取一个值并将其发送回调用该函数的行。 返回值允许您将程序的大部分繁重工作转移到函数中,这可以简化程序的主体。

返回简单的值

让我们看一个接受名字和姓氏并返回格式整齐的全名的函数:

def get_formatted_name(first_name, last_name):
    """Return a full name, neatly formatted."""
    full_name = f"{first_name} {last_name}" (1)
    return full_name.title() (2)

musician = get_formatted_name('jimi', 'hendrix') (3)
print(musician)
1 get_formatted_name() 的定义将名字和姓氏作为参数。 该函数将这两个名称组合起来,在它们之间添加一个空格,并将结果赋值给 full_name 。
2 full_name 的值转换为 title case,然后返回给调用行 。
3 当您调用一个返回值的函数时,您需要提供一个可以将返回值分配给的变量。 在这种情况下,返回值被分配给变量 musician 。

输出显示了一个格式整齐的名字,由人名的各个部分组成:

Jimi Hendrix

格式化名称似乎是一项艰巨的工作,而我们本可以写:

print("Jimi Hendrix")

但是,当您考虑使用需要分别存储许多名字和姓氏的大型程序时,这似乎需要做很多工作才能获得格式整齐的名字,函数像 get_formatted_name() 变得非常有用。 您分别存储名字和姓氏,然后在您想要显示全名时调用此函数。

让实参变成可选的

有时使参数可选是有意义的,这样使用该函数的人可以选择仅在需要时提供额外信息。 您可以使用默认值使参数可选。

例如,假设我们想扩展 get_formatted_name() 来处理中间名。 第一次尝试包含中间名可能如下所示:

def get_formatted_name(first_name, middle_name, last_name):
    """Return a full name, neatly formatted."""
    full_name = f"{first_name} {middle_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)

此函数在给定名字、中间名和姓氏时起作用。 该函数接受名称的所有三个部分,然后从中构建一个字符串。 该函数在适当的地方添加空格并将全名转换为首字母大写:

John Lee Hooker

但是中间名并不总是需要的,如果您尝试仅使用名字和姓氏来调用它,那么编写的这个函数将不起作用。 为了使中间名可选,我们可以给 middle_name 参数一个空的默认值并忽略该参数,除非用户提供一个值。 为了使 get_formatted_name() 在没有中间名的情况下工作,我们将 middle_name 的默认值设置为空字符串并将其移动到参数列表的末尾:

def get_formatted_name(first_name, last_name, middle_name=''):
    """Return a full name, neatly formatted."""
    if middle_name: (1)
        full_name = f"{first_name} {middle_name} {last_name}"
    else: (2)
        full_name = f"{first_name} {last_name}"
    return full_name.title()

musician = get_formatted_name('jimi', 'hendrix')
print(musician)

musician = get_formatted_name('john', 'hooker', 'lee') (3)
print(musician)

在此示例中,名称由三个可能的部分构成。 因为总是有名字和姓氏,所以这些参数在函数定义中排在第一位。 中间名是可选的,所以它列在定义的最后,它的默认值是一个空字符串。

1 在函数体中,我们检查是否提供了中间名。 Python 将非空字符串解释为 True,因此如果中间名参数在函数调用中,条件测试 if middle_name 的计算结果为 True。 如果提供了中间名,则将名字、中间名和姓氏组合起来形成一个全名。 然后将此名称更改为标题大小写并返回到函数调用行,在那里它被分配给变量 musician 并打印出来。
2 如果没有提供中间名,则空字符串将无法通过 if 测试,并且运行 else 块。 全名仅由名字和姓氏构成,格式化后的名称将返回到调用行,并在调用行中分配给音乐家并打印出来。
3 使用名字和姓氏调用此函数非常简单。 但是,如果我们使用中间名,我们必须确保中间名是最后传递的参数,这样 Python 才能正确匹配位置参数。

我们函数的这个修改版本适用于只有名字和姓氏的人,它也适用于有中间名的人:

Jimi Hendrix
John Lee Hooker

可选值允许函数处理广泛的用例,同时让函数调用尽可能简单。

返回字典

函数可以返回您需要的任何类型的值,包括更复杂的数据结构,如列表和字典。 例如,以下函数接受姓名的一部分并返回表示人的字典:

def build_person(first_name, last_name):
    """Return a dictionary of information about a person."""
    person = {'first': first_name, 'last': last_name} (1)
    return person (2)

musician = build_person('jimi', 'hendrix')
print(musician) (3)
1 函数 build_person() 接受名字和姓氏,并将这些值放入字典。 first_name 的值存储在键“first”中,last_name 的值存储在键“last”中。
2 然后,返回表示该人的整个字典。
3 返回值被打印出来,原始的两条文本信息现在存储在字典中:
{'first': 'jimi', 'last': 'hendrix'}

此函数接收简单的文本信息并将其放入更有意义的数据结构中,使您可以处理信息而不仅仅是打印它。 字符串 'jimi' 和 'hendrix' 现在被标记为名字和姓氏。 您可以轻松地扩展此函数以接受可选值,例如中间名、年龄、职业或您想要存储的关于某个人的任何其他信息。 例如,以下更改还允许您存储一个人的年龄:

def build_person(first_name, last_name, age=None):
    """Return a dictionary of information about a person."""
    person = {'first': first_name, 'last': last_name}
    if age:
        person['age'] = age
    return person

musician = build_person('jimi', 'hendrix', age=27)
print(musician)

我们在函数定义中添加一个新的可选参数 age,并为该参数分配特殊值 None,当变量没有分配特定值时使用该值。 您可以将 None 视为占位符值。 在条件测试中,None 的计算结果为 False。 如果函数调用包含年龄值,则该值存储在字典中。 这个函数总是存储一个人的名字,但也可以修改它来存储你想要的关于一个人的任何其他信息。

结合使用函数和while循环

到目前为止,您可以使用具有所有 Python 结构的函数。 例如,让我们使用带有 while 循环的 get_formatted_name() 函数来更正式地问候用户。 这是第一次尝试使用他们的名字和姓氏来问候人们:

def get_formatted_name(first_name, last_name):
    """Return a full name, neatly formatted."""
    full_name = f"{first_name} {last_name}"
    return full_name.title()

# This is an infinite loop!
while True:
    print("\nPlease tell me your name:") (1)
    f_name = input("First name: ")
    l_name = input("Last name: ")

    formatted_name = get_formatted_name(f_name, l_name)
    print(f"\nHello, {formatted_name}!")
1 对于此示例,我们使用不涉及中间名的简单版本的 get_formatted_name()。 while 循环要求用户输入他们的名字,我们分别提示输入他们的名字和姓氏。

但是这个 while 循环有一个问题:我们没有定义退出条件。 当你要求一系列输入时,你把退出条件放在哪里? 我们希望用户能够尽可能轻松地退出,因此每个提示都应该提供一种退出方式。 break 语句提供了一种在任一提示符下退出循环的直接方法:

def get_formatted_name(first_name, last_name):
    """Return a full name, neatly formatted."""
    full_name = f"{first_name} {last_name}"
    return full_name.title()

# This is an infinite loop!
while True:
    print("\nPlease tell me your name:")
    print("(enter 'q' at any time to quit)")

    f_name = input("First name: ")
    if f_name == 'q':
        break

    l_name = input("Last name: ")
    if l_name == 'q':
        break

    formatted_name = get_formatted_name(f_name, l_name)
    print(f"\nHello, {formatted_name}!")

我们添加一条消息,通知用户如何退出,然后如果用户在任一提示中输入退出值,我们就会跳出循环。 现在程序将继续问候人们,直到有人输入 q 中的任何一个名字:

Please tell me your name:
(enter 'q' at any time to quit)
First name: eric
Last name: matthes

Hello, Eric Matthes!

Please tell me your name:
(enter 'q' at any time to quit)
First name: q
自己试试
8-6.City Names

编写一个名为 city_country() 的函数,它接收城市名称及其国家/地区的名称。 该函数应返回格式如下的字符串:“Santiago, Chile” 使用至少三个城市-国家对调用您的函数,并打印返回的值。

8-7.Album

编写一个名为 make_album() 的函数来构建一个描述音乐专辑的字典。 该函数应接收艺术家姓名和专辑名称,并应返回包含这两项信息的字典。 使用函数制作三个字典代表不同的专辑。 打印每个返回值以表明字典正确存储了专辑信息。 使用 None 向 make_album() 添加一个可选参数,允许您存储专辑中的歌曲数量。 如果呼叫线路包含歌曲数量的值,请将该值添加到专辑的字典中。 至少进行一个新的函数调用,其中包括专辑中的歌曲数量。

8-8.User Albums

从练习 8-7 中的程序开始。 编写一个 while 循环,允许用户输入专辑的艺术家和标题。 获得该信息后,使用用户的输入调用 make_album() 并打印创建的字典。 请务必在 while 循环中包含一个退出值。