8.3 返回值

函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。函数返回的值被称为返回值 。在函数中,可使用return 语句将值返回到调用函数的代码行。返回值让你能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。

8.3.1 返回简单值

下面来看一个函数,它接受名和姓并返回整洁的姓名:

formatted_name.py

  1. def get_formatted_name(first_name, last_name):
  2. """返回整洁的姓名"""
  3. full_name = first_name + ' ' + last_name
  4. return full_name.title()
  5. musician = get_formatted_name('jimi', 'hendrix')
  6. print(musician)
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  

函数get_formatted_name() 的定义通过形参接受名和姓(见❶)。它将姓和名合而为一,在它们之间加上一个空格,并将结果存储在变量full_name 中(见❷)。然后,将full_name 的值转换为首字母大写格式,并将结果返回到函数调用行(见❸)。

调用返回值的函数时,需要提供一个变量,用于存储返回的值。在这里,将返回值存储在了变量musician 中(见❹)。输出为整洁的姓名:

  1. Jimi Hendrix
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  

我们原本只需编写下面的代码就可输出整洁的姓名,相比于此,前面做的工作好像太多了:

  1. print("Jimi Hendrix")
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  

但在需要分别存储大量名和姓的大型程序中,像get_formatted_name() 这样的函数非常有用。你分别存储名和姓,每当需要显示姓名时都调用这个函数。

8.3.2 让实参变成可选的

有时候,需要让实参变成可选的,这样使用函数的人就只需在必要时才提供额外的信息。可使用默认值来让实参变成可选的。

例如,假设我们要扩展函数get_formatted_name() ,使其还处理中间名。为此,可将其修改成类似于下面这样:

  1. def get_formatted_name(first_name, middle_name, last_name):
  2. """返回整洁的姓名"""
  3. full_name = first_name + ' ' + middle_name + ' ' + last_name
  4. return full_name.title()
  5. musician = get_formatted_name('john', 'lee', 'hooker')
  6. print(musician)
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  

只要同时提供名、中间名和姓,这个函数就能正确地运行。它根据这三部分创建一个字符串,在适当的地方加上空格,并将结果转换为首字母大写格式:

  1. John Lee Hooker
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  

然而,并非所有的人都有中间名,但如果你调用这个函数时只提供了名和姓,它将不能正确地运行。为让中间名变成可选的,可给实参middle_name 指定一个默认值——空字符串,并在用户没有提供中间名时不使用这个实参。为让get_formatted_name() 在没有提供中间名时依然可行,可给实参middle_name 指定一个默认值——空字符串,并将其移到形参列表的末尾:

  1. def get_formatted_name(first_name, last_name, middle_name=''):
  2. """返回整洁的姓名"""
  3. if middle_name:
  4. full_name = first_name + ' ' + middle_name + ' ' + last_name
  5. else:
  6. full_name = first_name + ' ' + last_name
  7. return full_name.title()
  8. musician = get_formatted_name('jimi', 'hendrix')
  9. print(musician)
  10. musician = get_formatted_name('john', 'hooker', 'lee')
  11. print(musician)
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  

在这个示例中,姓名是根据三个可能提供的部分创建的。由于人都有名和姓,因此在函数定义中首先列出了这两个形参。中间名是可选的,因此在函数定义中最后列出该形参,并将其默认值设置为空字符串(见❶)。

在函数体中,我们检查是否提供了中间名。Python将非空字符串解读为True ,因此如果函数调用中提供了中间名,if middle_name 将为True (见❷)。如果提供了中间名,就将名、中间名和姓合并为姓名,然后将其修改为首字母大写格式,并返回到函数调用行。在函数调用行,将返回的值存储在变量musician 中;然后将这个变量的值打印出来。如果没有提供中间名,middle_name 将为空字符串,导致if 测试未通过,进而执行else 代码块(见❸):只使用名和姓来生成姓名,并将设置好格式的姓名返回给函数调用行。在函数调用行,将返回的值存储在变量musician 中;然后将这个变量的值打印出来。

调用这个函数时,如果只想指定名和姓,调用起来将非常简单。如果还要指定中间名,就必须确保它是最后一个实参,这样Python才能正确地将位置实参关联到形参(见❹)。

这个修改后的版本适用于只有名和姓的人,也适用于还有中间名的人:

  1. Jimi Hendrix
  2. John Lee Hooker
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  

可选值让函数能够处理各种不同情形的同时,确保函数调用尽可能简单。

8.3.3 返回字典

函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。例如,下面的函数接受姓名的组成部分,并返回一个表示人的字典:

person.py

  1. def build_person(first_name, last_name):
  2. """返回一个字典,其中包含有关一个人的信息"""
  3. person = {'first': first_name, 'last': last_name}
  4. return person
  5. musician = build_person('jimi', 'hendrix')
  6. print(musician)
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  

函数build_person() 接受名和姓,并将这些值封装到字典中(见❶)。存储first_name 的值时,使用的键为'first' ,而存储last_name 的值时,使用的键为'last' 。最后,返回表示人的整个字典(见❷)。在❸处,打印这个返回的值,此时原来的两项文本信息存储在一个字典中:

  1. {'first': 'jimi', 'last': 'hendrix'}
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  

这个函数接受简单的文本信息,将其放在一个更合适的数据结构中,让你不仅能打印这些信息,还能以其他方式处理它们。当前,字符串'jimi''hendrix' 被标记为名和姓。你可以轻松地扩展这个函数,使其接受可选值,如中间名、年龄、职业或你要存储的其他任何信息。例如,下面的修改让你还能存储年龄:

  1. def build_person(first_name, last_name, age=''):
  2. """返回一个字典,其中包含有关一个人的信息"""
  3. person = {'first': first_name, 'last': last_name}
  4. if age:
  5. person['age'] = age
  6. return person
  7. musician = build_person('jimi', 'hendrix', age=27)
  8. print(musician)
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  

在函数定义中,我们新增了一个可选形参age ,并将其默认值设置为空字符串。如果函数调用中包含这个形参的值,这个值将存储到字典中。在任何情况下,这个函数都会存储人的姓名,但可对其进行修改,使其也存储有关人的其他信息。

8.3.4 结合使用函数和while 循环

可将函数同本书前面介绍的任何Python结构结合起来使用。例如,下面将结合使用函数get_formatted_name()while 循环,以更正规的方式问候用户。下面尝试使用名和姓跟用户打招呼:

greeter.py

  1. def get_formatted_name(first_name, last_name):
  2. """返回整洁的姓名"""
  3. full_name = first_name + ' ' + last_name
  4. return full_name.title()
  5. # 这是一个无限循环!
  6. while True:
  7. print("\nPlease tell me your name:")
  8. f_name = input("First name: ")
  9. l_name = input("Last name: ")
  10. formatted_name = get_formatted_name(f_name, l_name)
  11. print("\nHello, " + formatted_name + "!")
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  

在这个示例中,我们使用的是get_formatted_name() 的简单版本,不涉及中间名。其中的while 循环让用户输入姓名:依次提示用户输入名和姓(见❶)。

但这个while 循环存在一个问题:没有定义退出条件。请用户提供一系列输入时,该在什么地方提供退出条件呢?我们要让用户能够尽可能容易地退出,因此每次提示用户输入时,都应提供退出途径。每次提示用户输入时,都使用break 语句提供了退出循环的简单途径:

  1. def get_formatted_name(first_name, last_name):
  2. """返回整洁的姓名"""
  3. full_name = first_name + ' ' + last_name
  4. return full_name.title()
  5. while True:
  6. print("\nPlease tell me your name:")
  7. print("(enter 'q' at any time to quit)")
  8. f_name = input("First name: ")
  9. if f_name == 'q':
  10. break
  11. l_name = input("Last name: ")
  12. if l_name == 'q':
  13. break
  14. formatted_name = get_formatted_name(f_name, l_name)
  15. print("\nHello, " + formatted_name + "!")
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  

我们添加了一条消息来告诉用户如何退出,然后在每次提示用户输入时,都检查他输入的是否是退出值,如果是,就退出循环。现在,这个程序将不断地问候,直到用户输入的姓或名为'q' 为止:

  1. Please tell me your name:
  2. (enter 'q' at any time to quit)
  3. First name: eric
  4. Last name: matthes
  5. Hello, Eric Matthes!
  6. Please tell me your name:
  7. (enter 'q' at any time to quit)
  8. First name: q
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  

动手试一试

8-6 城市名 :编写一个名为city_country() 的函数,它接受城市的名称及其所属的国家。这个函数应返回一个格式类似于下面这样的字符串:

  1. "Santiago, Chile"
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  

至少使用三个城市-国家对调用这个函数,并打印它返回的值。

8-7 专辑 :编写一个名为make_album() 的函数,它创建一个描述音乐专辑的字典。这个函数应接受歌手的名字和专辑名,并返回一个包含这两项信息的字典。使用这个函数创建三个表示不同专辑的字典,并打印每个返回的值,以核实字典正确地存储了专辑的信息。

给函数make_album() 添加一个可选形参,以便能够存储专辑包含的歌曲数。如果调用这个函数时指定了歌曲数,就将这个值添加到表示专辑的字典中。调用这个函数,并至少在一次调用中指定专辑包含的歌曲数。

8-8 用户的专辑 :在为完成练习8-7编写的程序中,编写一个while 循环,让用户输入一个专辑的歌手和名称。获取这些信息后,使用它们来调用函数make_album() ,并将创建的字典打印出来。在这个while 循环中,务必要提供退出途径。