Python编程:从入门到实践(学习笔记-Charpter 8)

Python编程:从入门到实践(学习笔记-Charpter 8)

十月 17, 2019

Chapter 8 : 函数

8.1  定义函数

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def greet_user():
    """显示简单的问候语"""
    print("Hello!")

    greet_user()

    #1.使用关键字def来定义一个函数,这就是函数定义,greet_user()是函数名,括号必不可少,以冒号结尾
    #2.紧跟着def greet_user() : 后面的所有缩进行构成了函数体;
    #3.""" ...""" 文档字符串的注解,用三引号括起来,Python使用它们来生成有关程序中函数的文档。
    #4.print() 是函数体内的唯一一行代码,greet_user()用来打印Hello!
    #5.调用函数需要:以此指定函数名以及用括号括起来的必要信息
  • 向函数传递信息

    1
    2
    3
    4
    5
    6
    7
    8
    def greet_user(username):
    """显示简单的问候语"""
    print("hello, " + username.title() + "!")

    greet_user('jesse') #'实参' ,实参要用单引号括起来

    #在greet_user( ) 的括号中添加 username , 让函数接受你给username指定的任何值
    #greet_user('jesse') 是将 jesse 这个信息传递给 username ,以便用在函数中
  • 实参和形参

    在上个实例中,要求给变量 username 指定一个值。调用这个函数并提供这种信息(人名)时,打印相应问候语。

    username : 形参(变量)。 (函数完成其工作所需要的一项信息)

    ‘jesse’ : 实参(确值)。 (调用函数时传递给函数的信息)

在调用函数时,将要让函数使用的信息放在括号内,在 greet_user('jesse' ) 中,将实参’jesse’ 传递给了函数greet_user( ),这个值被存储在形参 username 中。

8.2  传递实参

向函数传递实参的方式有:

  • 位置实参(要求实参的顺序形参的顺序相同)

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      #定义一种动物类型和名字
      def describe_pet(animal_type, pet_name):
      """显示宠物的信息"""
      print("\nI have a " + animal_type + ".")
      print("My" + anmial_type + "'s name is " + pet_name.title() + ".")

      describle_pet('hamster', 'harry')

      #调用describe_pet()时,需要按顺序提供一种动物类型和一个名字。
      #实参 'hamster'存储在 形参 animal_typ中,而 实参'Harry'存储在 形参 pet_name中
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      #调用函数多次
      #位置实参的 顺序很重要
      describe_pet('hamster', 'harry')
      describe_pet('dog', 'willie')

      '''
      1.调用函数多次是一种效率极高的工作方式
      2.只需要在函数中编写描述宠物的代码一次,然后每当需要描述新的宠物时,都可调用这个函数
      3.在函数中,可根据需要使用任意数量的位置实参,Python将按顺序将函数调用中的实参关联到函数定义中相应的形参
      '''
  • 关键字实参

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      #关键字参数 是传递给函数的名称——值对
      #关键字参数无需考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途。
      def describe_pet(animal_type, pet_name):
      """显示宠物的信息"""
      print("\nI have a " + animal_type + ".")
      print("My " + animal_type + "'s name is " + pet_name.title() + ".")

      describe_pet(animal_type = 'hamster', pet_name = 'harry')

      #用 = 来指定实参,来避免顺序错误
      describe_pet(pet_name = 'harry', animal_type = 'hamster')

      #使用关键实参时,务必准确地指定函数定义中的形参名
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #默认值
      #在调用函数中给形参提供了实参时,Python将使用指定的实参值;否则,将使用形参的默认值
      def describ_pet(pet_name, animal_type = 'dog'):
      #在形参列表中必须先列出没有默认值的形参,再列出有默认值的实参
      """显示宠物的信息"""
      print("\nI have a " + animal_type + ".")
      print("My " + animal_type + "'s name is " + pet_name.title() + ".")

      describe_pet(pet_name = 'willie')

      #函数调用中只包含宠物的名字,这个实参将关联到函数定义中的第一个形参
      describe_pet('willie')
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      #等效的函数调用
      def describe_pet(pet_name, animal_type = 'dog'):

      ....

      #多种形式调用
      describe_pet('willie')
      describe_pet(pet_name = 'willie')
      describe_pet('harry', 'hamster')
      describe_pet(pet_name = 'harry', animal_type = 'hamster')
      describe_pet(animal_type = 'hamster', pet_name = 'harry')

      '''
      使用那种调用方式无关紧要,只要函数调用能生成你希望的输出就行
      '''

8.3  返回值 return

  • 返回简单值

    1
    2
    3
    4
    5
    6
    7
    8
    def get_formatted_name(first_name, last_name):
    """返回整洁的姓名"""
    full_name = first_name + ' ' + last_name
    return full_name.title()

    #调用返回值的函数时,需要提供一个变量,用于存储返回值
    musician = get_formatted_name('jimi', 'hendrix')
    print(musician)
  • 让实参变成可选的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def get_formatted_name(first_name, middle_name, last_name):
    """返回整洁的姓名"""
    full_name = first_name + ' ' + middle_name + ' ' + last_name
    return full_name.title()

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

    #为让get_formatted_name()在没有提供中间名时依然可行,可给实参middle_name 指定一个默认值————空字符串,并将其移动到形参列表的末尾:
    def get_formatted_name(first_name, last_name, middle_name = ''):
    """返回整洁的姓名"""
    if middle_name:
    full_name = first_name + ' ' + middle_name + ' ' + last_name
    else:
    full_name = first_name + ' ' + last_name
    return full_name.title()

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

    musician = get_formatted_name('john', 'lee', 'hooker')
    print(musician)
  • 返回字典

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    def build_person(first_name, last_name):
    """返回一个字典,其实包含有关一个人的信息"""
    person = {'first': first_name, 'last': last_name}
    return person

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

    #存储年龄
    def build_person(first_name, last_name, age = ''):
    """返回一个字典,其实包含有关一个人的信息"""
    person = {'first': first_name, 'last': last_name}
    if age: #表示如果age不为空,则执行下面语句
    person['age'] = age
    return person

    musician = build_person('jimi', 'hendrix', age = 27)
    print(musician)
  • 结合使用函数和while循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    def get_formatted_name(first_name, last_name):
    """返回整洁的姓名"""
    full_name = first_name + ' ' + last_name
    return full_name.title()

    #这是一个无限循环!
    while True:
    print("\nPlease tell me your name:")
    f_name = input('First name: ')
    l_name = input("Last name: ")

    formatted_name = get_formatted_name(f_name, l_name)
    print("\nHello, " + formatted_name + "!")

    #添加退出路径
    while Ture:
    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("\nHello, " + formatted_name + "!")

    ——-综合实例——

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #8-8 用户的专辑
    def make_album(singer_name, album_name, song_number = ''): #''之间不要空一格
    Album_info = {'name': singer_name, 'album': album_name}
    if song_number: # song_number 为空时是false, 当有值时执行下面代码行
    Album_info['song_number'] = number
    return Album_info

    while True:
    print("(enter 'q' at any time to quit)")

    singer_name = input("请输入歌手名字: ")
    if singer_name == 'q':
    break

    album_name = input("请输入专辑的名字: ")
    if album_name == 'q':
    break

    number = input("请输入歌曲数量: ")
    if number == 'q':
    break
    information = make_album(singer_name, album_name, song_number = number)
    print('')
    print("歌手及其专辑信息:")
    print(information)

8.4 传递列表

1
2
3
4
5
6
7
8
9
10
11
12
#将greet_users()定义成接受一个名字列表,并将其存储在形参names中
def greet_users(names):
"""向列表中的每位用户都发出简单的问候"""

#这个函数遍历收到的列表,并对其中的每位用户都打印一条问候语
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)

#定义一个用户列表——username,然后调用函数greet_users()
usernames = ['hannah', 'try', 'margot']
greet_users(usernames)
  • 在函数中修改列表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #首先创建一个列表,其中包含一些要打印的设计
    unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
    completed_models = []

    #模拟打印每个设计,直到没有未打印的设计为止
    # 打印每个设计后,都将其移到列表completed_models中
    while unprinted_designs:
    current_design = unprinted_designs.pop() #pop删除列表末尾元素,并可以接着使用值

    #模拟根据设计制作3D打印模型的过程
    print("Printing model : " + current_design)
    completed_models.append(current_design) #append 在列表末尾添加新元素

    # 显示打印好的所有模型
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
    print(completed_model)
    • 修改优化上述代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      def print_models(unprinted_designs, completed_models):
      """
      模拟打印每个设计,直到没有未打印的设计为止
      打印每个设计后,都将其移到列表completed_models中
      """
      while unprinted_designs:
      current_design = unprinted_designs.pop()

      #模拟根据设计制作3D打印模型的过程
      print("Printing model: " + current_design)
      completed_models.append(current_design)

      def show_completed_models(completed_models):
      """显示打印好的所有模型"""
      print("\nThe following models have been printed: ")
      for completed_model in completed_models:
      print(completed_model)


      unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
      completed_models = []

      print_models(unprinted_designs, completed_models)
      show_completed_models(completed_models)
  • 禁止函数修改列表

    1
    2
    3
    4
    5
    #将列表的副本传递给函数
    function_name(list_name[:])

    #切片表示[ : ]创建列表的副本,如果不想清空未打印的设计表,可像下面这样调用print_models()
    print_models(unprinted_designs[:], completed_models)

8.5 传递任意数量的实参

1
2
3
4
5
6
7
8
9
10
11
def make_pizza(*toppings):
"""打印顾客点的所有配料"""
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print("- " + toppinging)

make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

# 形参名*toppings中的星号让Python创建一个名为toppings的 空元组,并将收到的所有值都封装在这个元组中
#使用一个值调用函数的情形,也能处理使用三个值来调用函数的情形。不管函授接受到多少实参,这种语法都管用。
  • 结合使用位置实参和任意数量实参(*形参放后面) 一个*元组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在 最后。
    def make_pizza(size, *toppings): #一个*是元组
    """概述要制作的披萨"""
    print("\n Making a " + str(size) +
    "-inch pizza with the following toppings: ")
    for topping in toppings:
    print("- " + topping)

    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
  • 使用任意数量的关键字实参 两个**字典

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #两个*是空字典
    def build_profile(first, last, **user_info):
    """创建一个字典,其中包含我们知道的有关用户的一切"""
    profile = {}
    profile['first_name'] = first #1
    profile['last_name'] = last
    for k, v in user_info.items(): #2
    profile[k] = v
    return profile

    user_profile = build_profile('albert', 'einstein',
    location = 'princeton',
    field = 'physics')
    print(user_profile)

    '''
    函数 build_profile() 的定义要求提供名和姓,同时允许用户根据需要提供任意数量的名称 — 值对。形参 **user_info 中的两个星号让 Python 创建一个名为 user_info 的空字典,并将收到的所有名称 — 值对都封装到这个字典中。在这个函数中,可以像访问其他字典那样访问 user_info 中的名称 — 值对。

    在 build_profile() 的函数体内,我们创建了一个名为 profile 的空字典,用于存储用户简介。在❶处,我们将名和姓加入到这个字典中,因为我们总是会从用户那里收到这两项信息。在❷处,我们遍历字典 user_info 中的键 — 值对,并将每个键 — 值对都加入到字典 profile 中。最后,我们将字典 profile 返回给函数调用行。

    我们调用 build_profile() ,向它传递名( 'albert' )、姓( 'einstein' )和两个键 — 值对( location='princeton' 和 field='physics' ),并将返回的 profile 存储在变量 user_profile 中,再打印这个变量:

    '''

8.6 将函数存储在模块中

  • 导入整个模块pizza.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #要让函数是可导入的,得先创建模块。模块 是扩展名为.py的文件,包含要导入到程序中的代码
    def make_pizza(size, *toppings):
    """概述要制作的披萨"""
    print("\n Making a " + str(size) +
    "-inch pizza with the following toppings: ")
    for topping in toppings:
    print("- " + topping)

    -----导入函数---------
    import pizza
    1
    2
    #如果你使用这种import语句导入了名为module_name.py的整个模块,就可使用下面的语法来使用其中任何一个函数:
    module_name.function_name()
  • 导入特定的函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #导入模块中的特定函数
    from module_name import function_name

    #通过用逗号分隔函数名,根据需要从模块中导入任意数量的函数:
    from module_name import function_0, function_1, function_2

    #对于前面的making_pizzas.py示例,如果只想导入要使用的函数,代码将类似于下面这样:
    from pizza import make_pizza

    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushroom', 'green peppers', 'extrea cheese')
  • 使用as函数指定别名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #如果要导入的函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名,函数的另一个名称,类似于外号,要给函数指定这种特殊外号,需要在导入它时这样做

    #下面给函数make_pizza()指定了别名mp(),这样在import语句中使用make_pizza as mp实现的
    #关键字as将函数重命名为你提供的别名
    from pizza import make_pizza as mp

    mp(16, 'pepperoni')
    mp(12, 'mushrooms', 'green peppers', 'extra cheese')

    #指定别名的通用语法:
    from module_name import function_name as fn
  • 使用as模块指定别名

    1
    2
    3
    4
    5
    6
    7
    import pizza as p

    p.make_pizza(16, 'pepperoni')
    p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

    #给模块指定别名的通用语法
    import module_name as mn
  • 导入模块中的所有函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #使用星号(*)运算符可以让Python导入模块中的所有函数:

    from pizza import *

    make_pizza(16, 'peppermoi')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

    '''警告'''
    # import 语句中的星号让 Python 将模块 pizza 中的每个函数都复制到这个程序文件中。由于导入了每个函数,可通过名称来调用每个函数,而无需使用句点表示法。然而,使用并非自己编写的大型模块时,最好不要采用这种导入方法:如果模块中有函数的名称与你的项目中使用的名称相同,可能导致意想不到的结果: Python 可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数。

    '''最佳做法 '''
    # 最佳的做法是,要么只导入你需要使用的函数,要么导入整个模块并使用句点表示法。这能让代码更清晰,更容易阅读和理解。

关于if __name__ == '__main__'

  • __name__ 是Python中一个隐含的变量它代表了模块的名字
  • 只有被Python解释器直接执行的模块的名字才是__main__
1
2
3
4
5
6
def mian():
#Todo : Add your code here
pass

if __name__ == '__main__':
main()

8.7 函数编写指南

  1. 应给函数指定描述性名称,且只在其中使用小写字母和下划线,描述性名称可以帮助你和别人明白代码想要做什么。给模块命名时也要遵循上述约定

  2. 每个函数都应包含简要地阐述其功能的注解,该注解应紧跟在函数定义后面,并采用文档字符串格式。 文档良好的函数让其他程序员只需阅读文档字符串中的描述就能够使用它,他们完全可以相信代码如描述的那样运行,只要知道函数名称、需要的实参以及返回值的类型,就能在自己的程序中使用它

  3. 给形参指定默认值时,等号两边不要有空格

    1
    def function_name(parameter_0, parameter_1='default value')
  4. 对于函数调用中的关键字实参,也需要遵循这个约定:

    1
    function_name(value_0, parameter_1='value')
  5. PEP 8建议代码行的长度不要超过79字符,这样就能在编辑器窗口适中的时候看到整个代码。如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来:

    1
    2
    3
    4
    5
    def function_name(parameter_0, 
    parameter_1, parameter_2,
    parameter_3, parameter_4
    parameter_5, parameter_6):
    function body...
  6. 如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始。

  7. 所有的import语句都应放在文件开头,唯一例外的情况情形是,在文件开头使用了注解来描述整个程序。