Python 编程快速入门

参考引用

  • Python编程:从入门到实践(第2版)

1. 环境配置

  • VSCode 中配置 Python 运行环境

2. 变量和简单数据类型

2.1 变量

  • 添加了一个名为 message 的变量。每个变量都指向一个值:与该变量相关联的信息为指向的值为文本 “Hello Python world!” 和 “Hello Python Crash Course world!”
    • 在程序中可随时修改变量的值,而Python将始终记录变量的最新值
    message = "Hello Python world!"
    print(message)
    
    message = "Hello Python Crash Course world!"
    print(message)
    
    Hello Python world!
    Hello Python Crash Course world!
    

2.1.1 变量的命名和使用

  • 变量名只能包含字母、数字和下划线。变量名能以字母或下划线打头,但不能以数字打头
    • 例如,可将变量命名为 message_1 ,但不能将其命名为 1_message
  • 变量名不能包含空格,但能使用下划线来分隔其中的单词
    • 例如,变量名 greeting_message 可行,但变量名 greeting message 会引发错误
  • 不要将 Python 关键字和函数名用作变量名
    • 即不要使用 Python 保留用于特殊用途的单词,如 print
  • 变量名应既简短又具有描述性
    • 例如,name 比 n 好,student_name 比 s_n 好,name_length 比 length_of_persons_name 好
  • 慎用小写字母 l 和大写字母 O ,因为它们可能被人错看成数字 1 和 0
  • 推荐使用小写的 Python 变量名而不是大写字母

2.2 字符串

  • 字符串就是一系列字符。在 Python 中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号
    "This is a string."
    'This is also a string.'
    
    'I told my friend, "Python is my favorite language!"'
    "The language 'Python' is named after Monty Python, not the snake."
    

2.2.1 使用方法修改字符串的大小写

  • 对于字符串,可执行的最简单的操作之一是修改其中单词的大小写
    • 很多时候无法依靠用户来提供正确的大小写,因此需要将字符串先转换为小写,再存储它们。以后需要显示这些信息时,再将其转换为最合适的大小写方式
    name = "Ada Lovelace"
    
    print(name.title())  # 单词首字母大写
    print(name.upper())
    print(name.lower())
    
    Ada Lovelace
    ADA LOVELACE
    ada lovelace
    

2.2.2 在字符串中使用变量

  • 在字符串中使用变量的值。例如,使用两个变量分别表示名和姓,然后合并这两个值以显示姓名
    • 要在字符串中插入变量的值,可在前引号前加上字母 f,再将要插入的变量放在花括号内,这种字符串名为 f 字符串,f 是 format(设置格式)的简写
    first_name = "ada"
    last_name = "lovelace"
    full_name = f"{first_name} {last_name}"
    
    message = f"Hello, {full_name.title()}!"
    
    print(message)
    
    Hello, Ada Lovelace!
    

2.2.3 使用制表符或换行符来添加空白

  • 空白泛指任何非打印字符,如空格、制表符和换行符
    • 要在字符串中添加制表符,可使用字符组合 \t
    • 要在字符串中添加换行符,可使用字符组合 \n
    print("\tPython")
    print("Languages:\nPython\nC\nJavaScript")
    
    	Python
    Languages:
    Python
    C
    JavaScript
    

2.2.4 删除空白

  • Python 能找出字符串开头和末尾多余的空白。要确保字符串末尾没有空白,可使用方法 rstrip(),要永久删除这个字符串中的空白,必须将删除操作的结果关联到变量
    • 还可剔除字符串开头的空白,或者同时剔除字符串两边的空白,分别使用方法 lstrip() 和 strip()
    favorite_language = 'python '
    print(favorite_language)
    
    favorite_language = favorite_language.rstrip()
    print(favorite_language)
    
    'python '
    'python'
    

2.3 数

2.3.1 整数

  • 在 Python 中,可对整数执行加(+)减(-)乘(*)除(/)运算
  • Python 使用两个乘号表示乘方运算
  • 在终端会话中,Python 直接返回运算结果
    print(2 + 3, 3 - 2, 2 * 3, 3 / 2, 3 ** 2, (2 + 3) * 4)
    
    5 1 6 1.5 9 20
    

2.3.2 浮点数

  • Python 将所有带小数点的数称为浮点数
    print(0.1 + 0.1, 2 * 0.1, 0.2 + 0.1, 3 * 0.1)
    
    # 结果包含的小数位数可能是不确定的
    0.2 0.2 0.30000000000000004 0.30000000000000004
    

2.3.3 整数和浮点数

  • 将任意两个数相除时,结果总是浮点数,即便这两个数都是整数且能整除
  • 如果一个操作数是整数,另一个操作数是浮点数,结果也总是浮点数
    print(4 / 2, 1 + 2.0, 2 * 3.0, 3.0 ** 2)
    
    2.0 3.0 6.0 9.0
    

2.3.4 数中的下划线

  • 书写很大的数时,可使用下划线将其中的数字分组,使其更清晰易读,当打印这种使用下划线定义的数时,Python 不会打印其中的下划线
    universe_age = 14_000_000_000
    print(universe_age)
    
    14000000000
    

2.3.5 同时给多个变量赋值

  • 可在一行代码中给多个变量赋值,这有助于缩短程序并提高其可读性。这种做法最常用于将一系列数赋给一组变量。只要变量和值的个数相同,Python 就能正确地将它们关联起来
    x, y, z = 0, 0, 0
    

2.3.6 常量

  • 常量类似于变量,但其值在程序的整个生命周期内保持不变。Python 没有内置的常量类型,但 Python 程序员会使用全大写来指出应将某个变量视为常量,其值应始终不变
    MAX_CONNECTIONS = 5000
    print(MAX_CONNECTIONS)
    

2.4 注释

  • 在 Python 中,注释用井号(# )标识。井号后面的内容都会被 Python 解释器忽略
    # 向大家问好。
    print("Hello Python people!")
    
    Hello Python people!
    

3. 列表简介

3.1 列表是什么

  • 列表由一系列按特定顺序排列的元素组成

    • 可以创建包含字母表中所有字母、数字 0~9 或所有家庭成员姓名的列表,也可以将任何东西加入列表中,其中的元素之间可以没有任何关系
    • 列表通常包含多个元素,因此可以给列表指定一个表示复数的名称(letters 、digits 或 names )
  • 在 Python 中,用方括号([])表示列表,并用逗号分隔其中的元素

    bicycles = ['trek', 'cannondale', 'redline', 'specialized']
    print(bicycles)
    
    ['trek', 'cannondale', 'redline', 'specialized']
    

3.1.1 访问列表元素

  • 列表是有序集合,因此要访问列表的任意元素,只需将该元素的位置(索引)告诉 Python 即可
    bicycles = ['trek', 'cannondale', 'redline', 'specialized']
    print(bicycles[0])
    print(bicycles[0].title())
    
    trek
    Trek
    

3.1.2 索引从 0 而不是 1 开始

  • 在 Python 中,第一个列表元素的索引为 0,而不是 1
  • Python 为访问最后一个列表元素提供了一种特殊语法。通过将索引指定为 -1
    bicycles = ['trek', 'cannondale', 'redline', 'specialized']
    
    print(bicycles[1])    # 访问第 2 个元素
    print(bicycles[3])    # 访问第 4 个元素
    print(bicycles[-1])   # 访问最后一个元素
    

3.1.3 使用列表中的各个值

  • 像使用其他变量一样使用列表中的各个值。例如,使用 f 字符串根据列表中的值来创建消息
    bicycles = ['trek', 'cannondale', 'redline', 'specialized']
    message = f"My first bicycle was a {bicycles[0].title()}."
    
    print(message)
    
    My first bicycle was a Trek.
    

3.2 修改、添加和删除元素

3.2.1 修改列表元素

  • 假设有一个摩托车列表,其中的第一个元素为 ‘honda’,如何修改它的值呢?
    motorcycles = ['honda', 'yamaha', 'suzuki']
    print(motorcycles)
    
    motorcycles[0] = 'ducati'
    print(motorcycles)
    
    ['honda', 'yamaha', 'suzuki']
    ['ducati', 'yamaha', 'suzuki']
    

3.2.2 在列表中添加元素

  • 在列表末尾添加元素

    • 在列表中添加新元素时,最简单的方式是将元素附加(append)到列表
    motorcycles = ['honda', 'yamaha', 'suzuki']
    print(motorcycles)
    
    motorcycles.append('ducati')
    print(motorcycles)
    
    ['honda', 'yamaha', 'suzuki']
    ['honda', 'yamaha', 'suzuki', 'ducati']
    
    • 方法 append() 让动态地创建列表易如反掌。例如,可以先创建一个空列表,再使用一系列函数调用 append() 来添加元素
    motorcycles = []
    motorcycles.append('honda')
    motorcycles.append('yamaha')
    motorcycles.append('suzuki')
    
    print(motorcycles)
    
    ['honda', 'yamaha', 'suzuki']
    
  • 在列表中插入元素

    • 使用方法 insert() 可在列表的任何位置添加新元素
    motorcycles = ['honda', 'yamaha', 'suzuki']
    motorcycles.insert(0, 'ducati')
    
    print(motorcycles)
    
    ['ducati', 'honda', 'yamaha', 'suzuki']
    

3.2.3 从列表中删除元素

  • 使用 del 语句删除元素

    • 如果知道要删除的元素在列表中的位置,可使用 del 语句
    • 使用 del 语句将值从列表中删除后,就无法再访问它
    motorcycles = ['honda', 'yamaha', 'suzuki']
    print(motorcycles)
    del motorcycles[0]
    
    print(motorcycles)
    
    ['honda', 'yamaha', 'suzuki']
    ['yamaha', 'suzuki']
    
  • 使用方法 pop() 删除元素

    • 方法 pop() 删除列表末尾的元素,并能够接着使用它。术语弹出(pop)源自这样的类比:列表就像一个栈,而删除列表末尾的元素相当于弹出栈顶元素
    motorcycles = ['honda', 'yamaha', 'suzuki']
    print(motorcycles)
    
    popped_motorcycle = motorcycles.pop()
    
    print(motorcycles)
    print(popped_motorcycle)
    
    ['honda', 'yamaha', 'suzuki']
    ['honda', 'yamaha']
    suzuki
    
  • 弹出列表中任何位置处的元素

    • 可以使用 pop() 来删除列表中任意位置的元素,只需在圆括号中指定要删除元素的索引即可
    • 每当使用 pop() 时,被弹出的元素就不再在列表中
    motorcycles = ['honda', 'yamaha', 'suzuki']
    first_owned = motorcycles.pop(1)
    
    print(f"The first motorcycle I owned was a {first_owned.title()}.")
    
    The first motorcycle I owned was a Yamaha.
    
  • 根据值删除元素

    • 不知道要从列表中删除的值所处的位置。而只知道要删除的元素的值,可使用方法 remove()
    • 使用 remove() 从列表中删除元素时,也可接着使用它的值
    • 方法 remove() 只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来确保将每个值都删除
    motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
    print(motorcycles)
    
    motorcycles.remove('ducati')
    
    print(motorcycles)
    
    ['honda', 'yamaha', 'suzuki', 'ducati']
    ['honda', 'yamaha', 'suzuki']
    

3.3 组织列表

3.3.1 使用 sort() 对列表永久排序

  • Python 方法 sort() 能够较为轻松地对列表进行排序。假设有一个汽车列表,并要让其中的汽车按字母顺序排列

    • 方法 sort() 永久性地修改列表元素的排列顺序。现在,汽车是按字母顺序排列的,再也无法恢复到原来的排列顺序
    cars = ['bmw', 'audi', 'toyota', 'subaru']
    cars.sort()
    
    print(cars)
    
    ['audi', 'bmw', 'subaru', 'toyota']
    
  • 还可以按与字母顺序相反的顺序排列列表元素

    cars = ['bmw', 'audi', 'toyota', 'subaru']
    cars.sort(reverse = True)
    
    print(cars)
    
    ['toyota', 'subaru', 'bmw', 'audi']
    

3.3.2 使用 sorted() 对列表临时排序

  • 要保留列表元素原来的排列顺序,同时以特定的顺序呈现它们,可使用函数 sorted()
    cars = ['bmw', 'audi', 'toyota', 'subaru']
    
    print("Here is the original list:", cars)
    print("Here is the sorted list:", sorted(cars))
    print("Here is the original list again:", cars)
    
    Here is the original list: ['bmw', 'audi', 'toyota', 'subaru']
    Here is the sorted list: ['audi', 'bmw', 'subaru', 'toyota']
    Here is the original list again: ['bmw', 'audi', 'toyota', 'subaru']
    

3.3.3 倒着打印列表

  • 要反转列表元素的排列顺序,可使用方法 reverse()。假设汽车列表是按购买时间排列的,可轻松地按相反的顺序排列其中的汽车
    • reverse() 不是按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序
    • reverse() 永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,只需对列表再次调用 reverse() 即可
    cars = ['bmw', 'audi', 'toyota', 'subaru']
    print(cars)
    
    cars.reverse()
    print(cars)
    
    ['bmw', 'audi', 'toyota', 'subaru']
    ['subaru', 'toyota', 'audi', 'bmw']
    

3.3.4 确定列表的长度

  • 使用函数 len() 可快速获悉列表的长度。在下面的示例中,列表包含四个元素,因此其长度为 4
    cars = ['bmw', 'audi', 'toyota', 'subaru']
    print(len(cars))
    

3.4 使用列表时避免索引错误

  • 使用列表经常会遇到一种错误。假设有一个包含三个元素的列表,却要求获取第四个元素
    • 每当需要访问最后一个列表元素时,都可使用索引 -1,仅当列表为空时,这种访问最后一个元素的方式才会导致错误
    motorcycles = ['honda', 'yamaha', 'suzuki']
    print(motorcycles[3])
    
    Traceback (most recent call last):
        File "motorcycles.py", line 2, in <module>
            print(motorcycles[3])
    IndexError: list index out of range
    

4. 操作列表

4.1 遍历整个列表

  • 假设有一个魔术师名单,需要将其中每个魔术师的名字都打印出来。下面使用 for 循环来打印魔术师名单中的所有名字
    magicians = ['alice', 'david', 'carolina'] 
    for magician in magicians: 
        print(f"{magician.title()}, that was a great trick!")
        print(f"I can't wait to see your next trick, {magician.title()}.\n")
        
    print("Thank you, everyone. That was a great magic show!")
    
    Alice, that was a great trick!
    I can't wait to see your next trick, Alice.
    
    David, that was a great trick!
    I can't wait to see your next trick, David.
    
    Carolina, that was a great trick!
    I can't wait to see your next trick, Carolina.
    
    Thank you, everyone. That was a great magic show!
    

4.2 避免缩进错误

4.2.1 忘记缩进

  • 对位于 for 语句后面且属于循环组成部分的代码行,一定要缩进。如果忘记缩进,Python 会提醒
    magicians = ['alice', 'david', 'carolina']
    for magician in magicians:
    print(magician)
    
    File "magicians.py", line 3
        print(magician)
        ^
    IndentationError: expected an indented block
    

4.2.2 忘记缩进额外的代码行

  • 下面是一个逻辑错误,从语法上看,代码是合法的,但由于存在逻辑错误,结果并不符合预期
    magicians = ['alice', 'david', 'carolina']
    for magician in magicians:
        print(f"{magician.title()}, that was a great trick!")
    print(f"I can't wait to see your next trick, {magician.title()}.\n")
    
    Alice, that was a great trick!
    David, that was a great trick!
    Carolina, that was a great trick!
    I can't wait to see your next trick, Carolina.
    

4.2.3 不必要的缩进

  • 如果不小心缩进了无须缩进的代码行,Python 将指出这一点
    • 函数调用 print() 无须缩进,因为它并非循环的组成部分
    message = "Hello Python world!"
        print(message)
    
    File "hello_world.py", line 2
        print(message)
        ^
    IndentationError: unexpected indent
    

4.3 创建数值列表

4.3.1 使用函数 range()

  • Python 函数 range() 能够轻松地生成一系列数
    for value in range(1, 5):
        print(value)
    
    1
    2
    3
    4
    

4.3.2 使用 range() 创建数字列表

  • 要创建数字列表,可使用函数 list() 将 range() 的结果直接转换为列表。如果将 range() 作为 list() 的参数,输出将是一个数字列表

    numbers = list(range(1, 6))
    print(numbers)
    
    [1, 2, 3, 4, 5]
    
  • 使用函数 range() 时,还可指定步长。为此,可给这个函数指定第三个参数,Python 将根据这个步长来生成数

    even_numbers = list(range(2, 11, 2)) 
    print(even_numbers)
    
    [2, 4, 6, 8, 10]
    
  • 将前 10 个整数的平方加入一个列表中

    squares = []
    for value in range(1,11):
        squares.append(value**2)  # 计算每个值的平方,并立即将结果附加到列表 squares 的末尾
    
    print(squares)
    
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    

4.3.3 对数字列表执行简单的统计计算

  • 有几个专门用于处理数字列表的 Python 函数找出数字列表的最大值、最小值和总和
    digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
    
    print(min(digits), max(digits), sum(digits))
    
    0 9 45
    

4.3.4 列表解析

  • 前面介绍的生成列表squares 的方式包含三四行代码,而列表解析让只需编写一行代码就能生成这样的列表
    • 列表解析将 for 循环和创建新元素的代码合并成一行,并自动附加新元素
    # for 循环将值 1~10 提供给表达式 value**2,此处无冒号
    squares = [value**2 for value in range(1, 11)]
    print(squares)
    
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    

4.4 使用列表的一部分

4.4.1 切片

  • 要创建切片,可指定要使用的第一个元素和最后一个元素的索引。与函数 range() 一样,Python 在到达第二个索引之前的元素后停止。要输出列表中的前三个元素,需要指定索引 0 和 3,这将返回索引为 0、1 和 2 的元素

    players = ['charles', 'martina', 'michael', 'florence', 'eli']
    
    print(players[0:3])
    
    ['charles', 'martina', 'michael']
    
  • 如果没有指定第一个索引,Python 将自动从列表开头开始

    players = ['charles', 'martina', 'michael', 'florence', 'eli']
    print(players[:4])
    
    ['charles', 'martina', 'michael', 'florence']
    
  • 要让切片终止于列表末尾

    players = ['charles', 'martina', 'michael', 'florence', 'eli']
    print(players[2:])
    
    ['michael', 'florence', 'eli']
    
  • 负数索引返回离列表末尾相应距离的元素,因此可以输出列表末尾的任意切片。例如,如果要输出名单上的最后三名队员

    players = ['charles', 'martina', 'michael', 'florence', 'eli']
    print(players[-3:])
    
    ['michael', 'florence', 'eli']
    

4.4.2 遍历切片

  • 如果要遍历列表的部分元素,可在 for 循环中使用切片。下面的示例遍历前三名队员,并打印他们的名字
    players = ['charles', 'martina', 'michael', 'florence', 'eli'] 
    
    print("Here are the first three players on my team:")
    for player in players[:3]:
        print(player.title())
    
    Here are the first three players on my team:
    Charles
    Martina
    Michael
    

4.4.3 复制列表

  • 要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:])。这让 Python 创建一个始于第一个元素、终止于最后一个元素的切片,即整个列表的副本
    my_foods = ['pizza', 'falafel', 'carrot cake'] 
    friend_foods = my_foods[:]  # 将 my_foods 的元素复制到新列表 friend_foods 中  
    # 如果只是将 my_foods 赋给 friend_foods ,就不能得到两个列表
    # friend_foods = my_foods
    
    # 在每个列表中都添加一种食品
    my_foods.append('cannoli')
    friend_foods.append('ice cream')
    
    print("My favorite foods are:")
    print(my_foods)
    
    print("\nMy friend's favorite foods are:")
    print(friend_foods)
    
    My favorite foods are:
    ['pizza', 'falafel', 'carrot cake', 'cannoli']
    
    My friend's favorite foods are:
    ['pizza', 'falafel', 'carrot cake', 'ice cream']
    

4.5 元组

  • 列表非常适合用于存储在程序运行期间可能变化的数据集,列表是可以修改的,然而,有时候需要创建一系列不可修改的元素,元组可以满足这种需求
    • Python 将不能修改的值称为不可变的 ,而不可变的列表被称为元组

4.5.1 定义元组

  • 元组看起来很像列表,但使用圆括号而非中括号来标识。定义元组后,就可使用索引来访问其元素,就像访问列表元素一样
    • 例如,如果有一个大小不应改变的矩形,可将其长度和宽度存储在一个元组中,从而确保它们是不能修改的
    dimensions = (200, 50)
    
    print(dimensions[0])
    print(dimensions[1])
    
    200
    50
    

4.5.2 遍历元组中的所有值

  • 像列表一样,也可以使用 for 循环来遍历元组中的所有值
    dimensions = (200, 50)
    for dimension in dimensions:
        print(dimension)
    
    200
    50
    

4.5.3 修改元组变量

  • 虽然不能修改元组的元素,但可以给存储元组的变量赋值
    dimensions = (200, 50)
    print("Original dimensions:")
    for dimension in dimensions:
        print(dimension)
    
    dimensions = (400, 100)
    print("\nModified dimensions:")
    for dimension in dimensions:
        print(dimension)
    
    Original dimensions:
    200
    50
    
    Modified dimensions:
    400
    100
    

5. if 语句

5.1 一个简单示例

  • 假设有一个汽车列表,并想将其中每辆汽车的名称打印出来。对于大多数汽车,应以首字母大写的方式打印其名称,但对于汽车名 ‘bmw’,应以全大写的方式打印。下面的代码遍历这个列表,并以首字母大写的方式打印其中的汽车名,不过对于 ‘bmw’,则以全大写的方式打印
    cars = ['audi', 'bmw', 'subaru', 'toyota']
    
    for car in cars:
        if car == 'bmw':
            print(car.upper())
        else:
            print(car.title())
    
    Audi
    BMW
    Subaru
    Toyota
    

5.2 条件测试

  • 每条 if 语句的核心都是一个值为 True 或 False 的表达式,这种表达式称为条件测试。Python 根据条件测试的值为 True 还是 False 来决定是否执行 if 语句中的代码

5.2.1 检查是否相等

  • 最简单的条件测试:检查变量的值是否与特定值相等
    car = 'bmw'
    
    print(car == 'bmw')
    print(car == 'audi')
    
    True
    False
    

5.2.2 检查是否不相等

  • 要判断两个值是否不等,可结合使用惊叹号和等号(!=)
  • 下面再使用一条 if 语句来演示如何使用不等运算符。将把要求的比萨配料赋给一个变量,再打印一条消息,指出顾客要求的配料是否是意式小银鱼
    requested_topping = 'mushrooms'
    
    if requested_topping != 'anchovies':
        print("Hold the anchovies!")
    
    Hold the anchovies!
    

5.2.3 数值比较

  • answer 的值(17)不是 42,因此缩进的代码块得以执行
    • 条件语句中可包含各种数学比较,如小于、小于等于、大于、大于等于
    answer = 17
    
    if answer != 42:
        print("That is not the correct answer. Please try again!")
    
    print(answer < 21, answer > 21, answer >= 21, answer <= 21)
    
    That is not the correct answer. Please try again!
    True False False True
    

5.2.4 检查多个条件

  • 可能想同时检查多个条件。例如,有时候需要在两个条件都为 True 时才执行相应的操作,而有时候只要求一个条件为 True

  • 使用 and 检查多个条件

    • 要检查是否两个条件都为 True ,可使用关键字 and 将两个条件测试合而为一。如果每个测试都通过了,整个表达式就为 True;如果至少一个测试没有通过,整个表达式就为 False
    age_0 = 22
    age_1 = 18
    
    print((age_0 >= 21) and (age_1 >= 21))
    
    False
    
  • 使用 or 检查多个条件

    • 关键字 or 也能够让你检查多个条件,但只要至少一个条件满足,就能通过整个测试。仅当两个测试都没有通过时,使用 or 的表达式才为 False
    age_0 = 22
    age_1 = 18
    
    print((age_0 >= 21) or (age_1 >= 21))
    
    True
    

5.2.5 检查特定值是否包含在列表中

  • 要判断特定的值是否已包含在列表中,可使用关键字 in
  • 要判断特定的值是否不包含在列表中,可使用关键字 not in
    available_toppings = ['mushrooms', 'olives', 'green peppers',
                          'pepperoni', 'pineapple', 'extra cheese']
    
    requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
    
    for requested_topping in requested_toppings:
        if requested_topping not in available_toppings:
            print(f"Adding {requested_topping}.")
        else:
            print(f"Sorry, we don't have {requested_topping}.")
            
    print("\nFinished making your pizza!")
    
    Sorry, we don't have mushrooms.
    Adding french fries.
    Sorry, we don't have extra cheese.
    
    Finished making your pizza!
    

5.2.6 布尔表达式

  • 布尔表达式是条件测试的别名。与条件表达式一样,布尔表达式的结果要么为 True ,要么为 False

5.3 if 语句

5.3.1 简单的 if 语句

  • 假设有一个表示某人年龄的变量,想知道这个人是否符合投票的年龄
    age = 19
    if age >= 18:
        print("You are old enough to vote!")
    
    You are old enough to vote!
    

5.3.2 if-else 语句

  • 需要在条件测试通过时执行一个操作,在没有通过时执行另一个操作,可使用 if-else 语句
    age = 17
    if age >= 18:
        print("You are old enough to vote!")
        print("Have you registered to vote yet?")
    else:
        print("Sorry, you are too young to vote.")
        print("Please register to vote as soon as you turn 18!")
    
    Sorry, you are too young to vote.
    Please register to vote as soon as you turn 18!
    

5.3.3 if-elif-else 结构

  • 经常需要检查超过两个的情形,为此可使用 Python 提供的 if-elif-else 结构
    age = 12
    
    if age < 4:
        price = 0
    elif age < 18:
        price = 25
    else:
        price = 40
    
    print(f"Your admission cost is ${price}.")
    
    Your admission cost is $25.
    

5.3.4 使用多个 elif 代码块

  • 可根据需要使用任意数量的 elif 代码块。例如,假设前述游乐场要给老年人打折,可再添加一个条件测试,判断顾客是否符合打折条件。下面假设对于 65岁(含)以上的老人,可半价购买门票
    age = 66
    
    if age < 4:
        price = 0
    elif age < 18:
        price = 25
    elif age < 65:
        price = 40
    elif age >= 65:
        price = 20
    # Python 并不要求 if-elif 结构后面必须有 else 代码块
    
    print(f"Your admission cost is ${price}.")
    
    Your admission cost is $20.
    

5.3.5 测试多个条件

  • 如果只想执行一个代码块,就使用 if-elif-else 结构,如果要执行多个代码块,就使用一系列独立的 if 语句
    requested_toppings = ['mushrooms', 'extra cheese']
    if 'mushrooms' in requested_toppings:
        print("Adding mushrooms.")
    if 'pepperoni' in requested_toppings:
        print("Adding pepperoni.")
    if 'extra cheese' in requested_toppings:
        print("Adding extra cheese.")
    
    print("\nFinished making your pizza!")
    
    Adding mushrooms.
    Adding extra cheese.
    
    Finished making your pizza!
    

5.4 使用 if 语句处理列表

5.4.1 检查特殊元素

  • 继续使用前面的比萨店示例。这家比萨店在制作比萨时,每添加一种配料都打印一条消息。通过创建一个列表,在其中包含顾客点的配料,并使用一个循环来指出添加到比萨中的配料
  • 然而,如果比萨店的青椒用完了,可在 for循环中包含一条 if 语句
    requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']
    
    for requested_topping in requested_toppings:
        if requested_topping == 'green peppers':
            print("Sorry, we are out of green peppers right now.")
        else:
            print(f"Adding {requested_topping}.")
    
    print("\nFinished making your pizza!")
    
    Adding mushrooms.
    Sorry, we are out of green peppers right now.
    Adding extra cheese.
    
    Finished making your pizza!
    

5.4.2 使用多个列表

  • 下面的示例定义了两个列表,其中第一个列表包含比萨店供应的配料,而第二个列表包含顾客点的配料。这次对于 requested_toppings 中的每个元素,都检查它是否是比萨店供应的配料,再决定是否在比萨中添加它
    available_toppings = ['mushrooms', 'olives', 'green peppers',
                          'pepperoni', 'pineapple', 'extra cheese']
    
    requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
    
    for requested_topping in requested_toppings:
        if requested_topping in available_toppings:
            print(f"Adding {requested_topping}.")
        else:
            print(f"Sorry, we don't have {requested_topping}.")
            
    print("\nFinished making your pizza!")
    
    
    Adding mushrooms.
    Sorry, we don't have french fries.
    Adding extra cheese.
    
    Finished making your pizza!
    

6. 字典

6.1 使用字典

  • 在 Python 中,字典是一系列键值对。每个键都与一个值相关联,可使用键来访问相关联的值。与键相关联的值可以是数、字符串、列表乃至字典,可将任何 Python 对象用作字典中的值
  • 在 Python中,字典用放在花括号({})中的一系列键值对表示
    • 键和值之间用冒号分隔,而键值对之间用逗号分隔
    • 在字典中,想存储多少个键值对都可以
    alien_0 = {'color' : 'green', 'points' : 5}
    

6.1.1 访问字典中的值

  • 要获取与键相关联的值,可依次指定字典名和放在方括号内的键
    alien_0 = {'color': 'green'}
    print(alien_0['color'])
    
    green
    
    alien_0 = {'color': 'green', 'points': 5}
    new_points = alien_0['points']
    
    print(f"You just earned {new_points} points!")
    
    You just earned 5 points!
    

6.1.2 添加键值对

  • 字典是一种动态结构,可随时在其中添加键值对
    • 要添加键值对,可依次指定字典名、用方括号括起的键和相关联的值
    • 在字典 alien_0 中添加两项信息:外星人 x x x 坐标和 y y y 坐标,能够在屏幕特定位置显示该外星人
    alien_0 = {'color': 'green', 'points': 5}
    print(alien_0)
    
    alien_0['x_position'] = 0
    alien_0['y_position'] = 25
    print(alien_0)
    
    {'color': 'green', 'points': 5}
    {'color': 'green', 'points': 5, 'y_position': 25, 'x_position': 0}
    

6.1.3 先创建一个空字典

  • 可先使用一对空花括号定义一个字典,再分行添加各个键值对
    • 使用字典来存储用户提供的数据或在编写能自动生成大量键值对的代码时,通常需要先定义一个空字典
    alien_0 = {}
    alien_0['color'] = 'green'
    alien_0['points'] = 5
    
    print(alien_0)
    
    {'color': 'green', 'points': 5}
    

6.1.4 修改字典中的值

  • 要修改字典中的值,可依次指定字典名、用方括号括起的键,以及与该键相关联的新值
    alien_0 = {'color': 'green'}
    print(f"The alien is {alien_0['color']}.")
    
    alien_0['color'] = 'yellow'
    print(f"The alien is now {alien_0['color']}.")
    
    The alien is green.
    The alien is now yellow.
    

6.1.5 删除键值对

  • 对于字典中不再需要的信息,可使用 del 语句将相应的键值对彻底删除。使用 del 语句时,必须指定字典名和要删除的键
    alien_0 = {'color': 'green', 'points': 5}
    print(alien_0)
    
    del alien_0['points']
    print(alien_0)
    
    {'color': 'green', 'points': 5}
    {'color': 'green'}
    

6.1.6 由类似对象组成的字典

  • 在前面的示例中,字典存储的是一个对象(游戏中的一个外星人)的多种信息,但也可以使用字典来存储众多对象的同一种信息
    favorite_languages = {
        'jen': 'python',
        'sarah': 'c',
        'edward': 'ruby',
        'phil': 'python',
        }
    
    language = favorite_languages['sarah'].title()
    print(f"Sarah's favorite language is {language}.")
    
    Sarah's favorite language is C.
    

6.1.7 使用 get() 来访问值

  • 使用放在方括号内的键从字典中获取感兴趣的值时,可能引发问题:如果指定的键不存在就会出错
    • 可使用方法 get() 在指定的键不存在时返回一个默认值,从而避免这样的错误
    • 方法 get() 的第一个参数用于指定键,是必不可少的;第二个参数为指定的键不存在时要返回的值,是可选的
    alien_0 = {'color': 'green', 'speed': 'slow'}
    point_value = alien_0.get('points', 'No point value assigned.')
    
    print(point_value)
    
    No point value assigned.
    

6.2 遍历字典

6.2.1 遍历所有键值对

  • 如果要获悉该用户字典中的所有信息,该如何办呢?可使用 for 循环来遍历这个字典
    user_0 = {
        'username': 'efermi',
        'first': 'enrico',
        'last': 'fermi',
        }
    
    # items() 返回一个键值对列表
    for key, value in user_0.items():
        print(f"\nKey: {key}")
        print(f"Value: {value}")
    
    Key: username
    Value: efermi
    
    Key: first
    Value: enrico
    
    Key: last
    Value: fermi
    

6.2.2 遍历字典中的所有键

  • 在不需要使用字典中的值时,方法 keys() 可以遍历字典中的所有键

    favorite_languages = {
        'jen': 'python',
        'sarah': 'c',
        'edward': 'ruby',
        'phil': 'python',
        }
    for name in favorite_languages.keys():
        print(name.title())
    
    Jen
    Sarah
    Edward
    Phil
    
  • 还可使用方法 keys() 确定某个人是否接受了调查。下面的代码确定 Erin 是否接受了调查

    favorite_languages = {
        'jen': 'python',
        'sarah': 'c',
        'edward': 'ruby',
        'phil': 'python',
        }
    if 'erin' not in favorite_languages.keys():
        print("Erin, please take our poll!")
    
    Erin, please take our poll!
    

6.2.3 按特定顺序遍历字典中的所有键

  • 要以特定顺序返回元素,一种办法是在 for 循环中对返回的键进行排序。为此,可使用函数 sorted() 来获得按特定顺序排列的键列表的副本
    favorite_languages = {
        'jen': 'python',
        'sarah': 'c',
        'edward': 'ruby',
        'phil': 'python',
        }
    # 列出字典中的所有键,并在遍历前对这个列表进行排序
    for name in sorted(favorite_languages.keys()):
        print(f"{name.title()}, thank you for taking the poll.")
    
    Edward, thank you for taking the poll.
    Jen, thank you for taking the poll.
    Phil, thank you for taking the poll.
    Sarah, thank you for taking the poll.
    

6.2.4 遍历字典中的所有值

  • 如果主要对字典包含的值感兴趣,可使用方法 values() 来返回一个值列表,不包含任何键
    favorite_languages = {
        'jen': 'python',
        'sarah': 'c',
        'edward': 'ruby',
        'phil': 'python',
        }
    print("The following languages have been mentioned:")
    for language in favorite_languages.values():
        print(language.title())
    
    The following languages have been mentioned:
    Python
    C
    Ruby
    Python
    
  • 上述做法提取字典中所有的值,而没有考虑是否重复
    • 涉及的值很少时,这也许不是问题,但如果被调查者很多,最终的列表可能包含大量重复项
    • 为剔除重复项,可使用集合(set),集合中的每个元素都必须是独一无二的
    ...
    for language in set(favorite_languages.values()):
        print(language.title())
    ...
    
    The following languages have been mentioned:
    Ruby
    C
    Python
    

可使用一对花括号直接创建集合,并在其中用逗号分隔元素

  • 集合和字典很容易混淆,因为它们都是用一对花括号定义的
  • 当花括号内没有键值对时,定义的很可能是集合
  • 不同于列表和字典,集合不会以特定的顺序存储元素

6.3 嵌套

  • 有时候,需要将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套

6.3.1 字典列表

  • 字典 alien_0 包含一个外星人的各种信息,但无法存储第二个外星人的信息。如何管理成群结队的外星人呢?一种办法是创建一个外星人列表,其中每个外星人都是一个字典,包含有关该外星人的各种信息
    # 创建一个用于存储外星人的空列表
    aliens = []
    
    # 创建 30 个绿色的外星人
    for alien_number in range(30):
        new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
        aliens.append(new_alien)
    
    # 使用 for 循环和 if 语句来修改部分外形人的颜色
    for alien in aliens[:3]:
        if alien['color'] == 'green':
            alien['color'] = 'yellow'
            alien['speed'] = 'medium'
            alien['points'] = 10
        
    # 使用一个切片来打印前 5 个外星人
    for alien in aliens[:5]:
        print(alien)
    print("...")
    print(f"Total number of aliens: {len(aliens)}")
    
    {'color': 'yellow', 'points': 10, 'speed': 'medium'}
    {'color': 'yellow', 'points': 10, 'speed': 'medium'}
    {'color': 'yellow', 'points': 10, 'speed': 'medium'}
    {'color': 'green', 'points': 5, 'speed': 'slow'}
    {'color': 'green', 'points': 5, 'speed': 'slow'}
    ...
    Total number of aliens: 30
    

6.3.2 在字典中存储列表

  • 有时候,需要将列表存储在字典中,而不是将字典存储在列表中
    • 例如,如何描述顾客点的比萨呢?如果使用列表,只能存储要添加的比萨配料;但如果使用字典,就不仅可在其中包含配料列表,还可包含其他有关比萨的描述
    # 创建一个字典,存储所点比萨的信息
    pizza = {
        'crust': 'thick',
        # 与 toppings 相关联的值是一个列表
        'toppings': ['mushrooms', 'extra cheese'],
        }
    
    # 如果函数调用 print() 中的字符串很长,可以在合适的位置分行
    # 只需要在每行末尾都加上引号,同时对于除第一行外的其他各行,都在行首加上引号并缩进
    print(f"You ordered a {pizza['crust']}-crust pizza "
        "with the following toppings:")
    
    # 从字典中提取配料列表
    for topping in pizza['toppings']:
        print("\t" + topping)
    
    You ordered a thick-crust pizza with the following toppings:
        mushrooms
        extra cheese
    
  • 当需要在字典中将一个键关联到多个值时,都可以在字典中嵌套一个列表
    • 在前面有关喜欢的编程语言的示例中,如果将每个人的回答都存储在一个列表中,被调查者就可选择多种喜欢的语言
    • 这种情况下,当遍历字典时,与每个被调查者相关联的都是一个语言列表,而不是一种语言
    • 因此,在遍历该字典的 for 循环中,需要再使用一个 for 循环来遍历与被调查者相关联的语言列表
    favorite_languages = {
        'jen': ['python', 'ruby'],
        'sarah': ['c'],
        'edward': ['ruby', 'go'],
        'phil': ['python', 'haskell'],
        }
    
    for name, languages in favorite_languages.items():
        print(f"\n{name.title()}'s favorite languages are:")
        for language in languages:
            print(f"\t{language.title()}")
    
    Jen's favorite languages are:
        Python
        Ruby
    
    Sarah's favorite languages are:
        C
    
    Edward's favorite languages are:
        Ruby
        Go
    
    Phil's favorite languages are:
        Python
        Haskell
    

6.3.3 在字典中存储字典

  • 可在字典中嵌套字典,但这样做时,代码可能很快复杂起来
  • 下面的程序中,存储了每位用户的三项信息:名、姓和居住地。为访问这些信息,遍历所有的用户名,并访问与每个用户名相关联的信息字典
    # 字典 users 中包含两个键:用户名 'aeinstein' 和 'mcurie' 
    # 与每个键相关联的值都是一个字典,其中包含用户的名、姓和居住地
    users = {
        'aeinstein': {
            'first': 'albert',
            'last': 'einstein',
            'location': 'princeton',
            },
    
        'mcurie': {
            'first': 'marie',
            'last': 'curie',
            'location': 'paris',
            },
        }
    
    for username, user_info in users.items():
        print(f"\nUsername: {username}")
        # 开始访问内部的字典。变量 user_info 包含用户信息字典
        # 而该字典包含三个键:'first'、'last' 和 'location' 
        full_name = f"{user_info['first']} {user_info['last']}"
        location = user_info['location']
    
        print(f"\tFull name: {full_name.title()}")
        print(f"\tLocation: {location.title()}")
    
    Username: aeinstein
    	Full name: Albert Einstein
    	Location: Princeton
    
    Username: mcurie
    	Full name: Marie Curie
    	Location: Paris
    

7. 用户输入和 while 循环

7.1 函数 input() 的工作原理

  • 函数input() 让程序暂停运行,等待用户输入一些文本。获取用户输入后,Python 将其赋给一个变量,以方便使用
    • 函数 input() 接受一个参数,输入被赋给变量 message
    prompt = "\nTell me something, and I will repeat it back to you:"
    prompt += "\nEnter 'quit' to end the program. "
    
    active = True
    while active:
        message = input(prompt)
        
        if message == 'quit':
            active = False  # 退出循环
        else:
            print(message)
    
    Tell me something, and I will repeat it back to you:
    Enter 'quit' to end the program. Hello
    Hello
    

7.1.1 使用 int() 来获取数值输入

  • 函数 int() 将数的字符串表示转换为数值表示
    height = input("How tall are you, in inches? ")
    height = int(height)
    
    if height >= 48:
        print("\nYou're tall enough to ride!")
    else:
        print("\nYou'll be able to ride when you're a little older.")
    
    How tall are you, in inches? 50
    
    You're tall enough to ride!
    

7.1.2 求模运算符

  • 处理数值信息时,求模运算符(%)是个很有用的工具,它将两个数相除并返回余数
  • 求模运算符不会指出一个数是另一个数的多少倍,只指出余数是多少
    number = input("Enter a number, and I'll tell you if it's even or odd: ")
    number = int(number)
    
    if number % 2 == 0:
        print(f"\nThe number {number} is even.")
    else:
        print(f"\nThe number {number} is odd.")
    
    Enter a number, and I'll tell you if it's even or odd: 9
    
    The number 9 is odd.
    

7.2 while 循环简介

  • for 循环用于针对集合中的每个元素都执行一个代码块,而 while 循环则不断运行,直到指定的条件不满足为止

7.2.1 使用 while 循环

  • 可使用 while 循环来数数,打印出 1-10 中的奇数
    current_number = 0
    while current_number < 10:
        current_number += 1
        if current_number % 2 == 0:
            continue
        
        print(current_number)
    
    1
    3
    5
    7
    9
    

7.2.2 使用标志

  • 在要求很多条件都满足才继续运行的程序中,可定义一个变量,用于判断整个程序是否处于活动状态。这个变量称为标志(flag),可以让程序在标志为 True 时继续运行,并在任何事件导致标志的值为 False 时让程序停止运行(代码参见 7.1 节)

7.2.3 使用 break 退出循环

  • 要退出 while 循环,不再运行循环中余下的代码,也不管条件测试结果如何,可使用 break 语句
  • break 语句用于控制程序流程,可用来控制哪些代码行将执行、哪些代码行不执行
    prompt = "\nPlease enter the name of a city you have visited:"
    prompt += "\n(Enter 'quit' when you are finished.) "
    
    # 以 while True 打头的循环将不断运行,直到遇到 break 语句
    while True:
        city = input(prompt)
        
        if city == 'quit':
            break
        else:
            print(f"I'd love to go to {city.title()}!")
    
    Please enter the name of a city you have visited:
    (Enter 'quit' when you are finished.) Beijing
    I'd love to go to Beijing!
    
    Please enter the name of a city you have visited:
    (Enter 'quit' when you are finished.) quit
    
    Process finished with exit code 0
    

7.2.4 在循环中使用 continue

  • 要返回循环开头,并根据条件测试结果决定是否继续执行循环,可使用 continue 语句,它不像 break 语句那样不再执行余下的代码并退出整个循环(代码参见 7.2.1 节)

7.2.5 避免无限循环

  • 每个 while 循环都必须有停止运行的途径,这样才不会没完没了地执行下去
  • 如果程序陷入无限循环,可按 Ctrl + C,也可关闭显示程序输出的终端窗口
    • x 的初始值为 1,但根本不会变。因此条件测试 x <= 5 始终为 True ,导致 while 循环没完没了地打印 1
    # 这个循环将没完没了地运行!
    x = 1
    while x <= 5:
        print(x)
    
    1
    1
    1
    ...
    

7.3 使用 while 循环处理列表和字典

  • 上述内容每次都只处理了一项用户信息:获取用户的输入,再将输入打印出来或做出应答;循环再次运行时,获悉另一个输入值并做出响应。然而,要记录大量的用户和信息,需要在 while 循环中使用列表和字典
  • for 循环是一种遍历列表的有效方式,但不应在 for 循环中修改列表。要在遍历列表的同时对其进行修改,可使用 while 循环

7.3.1 在列表之间移动元素

  • 假设有一个列表包含新注册但还未验证的网站用户。验证这些用户后,如何将他们移到另一个已验证用户列表中呢?一种办法是使用一个 while 循环,在验证用户的同时将其从未验证用户列表中提取出来,再将其加入另一个已验证用户列表中
    # 首先,创建一个待验证用户列表和一个用于存储已验证用户的空列表
    unconfirmed_users = ['alice', 'brian', 'candace']
    confirmed_users = []
    
    # 验证每个用户,直到列表 unconfirmed_users 变成空的
    while unconfirmed_users:
        # 从列表 unconfirmed_users 末尾删除未验证的用户
        current_user = unconfirmed_users.pop()
        
        print(f"Verifying user: {current_user.title()}")
        # 将每个经过验证的用户都移到已验证用户列表中
        confirmed_users.append(current_user)
        
    # 显示所有已验证的用户
    print("\nThe following users have been confirmed:")
    for confirmed_user in confirmed_users:
        print(confirmed_user.title())
    
    Verifying user: Candace
    Verifying user: Brian
    Verifying user: Alice
    
    The following users have been confirmed:
    Candace
    Brian
    Alice
    

7.3.2 删除为特定值的所有列表元素

  • 假设有一个宠物列表,其中包含多个值为 ‘cat’ 的元素。要删除所有这些元素,可不断运行一个 while 循环,直到列表中不再包含值 ‘cat’
    pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
    print(pets)
    
    while 'cat' in pets:
        pets.remove('cat')
        
    print(pets)
    
    ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
    ['dog', 'dog', 'goldfish', 'rabbit']
    

7.3.3 使用用户输入来填充字典

  • 可使用 while 循环提示用户输入任意多的信息。下面创建一个调查程序,其中的循环每次执行时都提示输入被调查者的名字和回答
    # 定义了一个空字典
    responses = {}
    
    # 设置一个标志,指出调查是否继续
    polling_active = True
    
    while polling_active:
        # 提示输入被调查者的名字和回答
        name = input("\nWhat is your name? ")
        response = input("Which mountain would you like to climb someday? ")
        
        # 将回答存储在字典中
        responses[name] = response
        
        # 看看是否还有人要参与调查
        repeat = input("Would you like to let another person respond? (yes/ no) ")
        if repeat == 'no':
            polling_active = False
            
    # 调查结束,显示结果
    print("\n--- Poll Results ---")
    for name, response in responses.items():
        print(f"{name} would like to climb {response}.")
    
    What is your name? Tom
    Which mountain would you like to climb someday? hah
    Would you like to let another person respond? (yes/ no) yes
    
    What is your name? Bob
    Which mountain would you like to climb someday? haha
    Would you like to let another person respond? (yes/ no) no
    
    --- Poll Results ---
    Tom would like to climb hah.
    Bob would like to climb haha.
    

8. 函数

8.1 定义函数

8.1.1 向函数传递信息

  • 通过添加 username ,可让函数接受 username 指定的任何值。现在,这个函数要求调用它时给 username 指定一个值。调用 greet_user() 时,可将一个名字传递给它
    # 使用关键字 def 来告诉 Python 要定义一个函数
    # 紧跟在 def greet_user() 后面的所有缩进行构成了函数体
    # 文档字符串用三引号括起,Python 使用它们来生成有关程序中函数的文档
    def greet_user(username):
        """显示简单的问候语"""
        print(f"Hello, {username.title()}!")
    
    # 要调用函数,可依次指定函数名以及用圆括号括起的必要信息
    greet_user('jesse')
    
    Hello, Jesse!
    

8.1.2 实参和形参

  • 在函数 greet_user() 的定义中,变量 username 是一个形参(parameter),即函数完成工作所需的信息
  • 在代码 greet_user(‘jesse’) 中,值 ‘jesse’ 是一个实参(argument),即调用函数时传递给函数的信息
  • 在 greet_user(‘jesse’) 中,将实参’jesse’ 传递给了函数 greet_user(),这个值被赋给了形参 username

8.2 传递实参

  • 函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。向函数传递实参的方式很多
    • 可使用位置实参,这要求实参的顺序与形参的顺序相同
    • 也可使用关键字实参 ,其中每个实参都由变量名和值组成
    • 还可使用列表和字典

8.2.1 位置实参

  • 调用函数时,Python 必须将函数调用中的每个实参都关联到函数定义中的一个形参。为此,最简单的关联方式是基于实参的顺序。这种关联方式称为位置实参
    def describe_pet(animal_type, pet_name):
        """显示宠物的信息"""
        print(f"\nI have a {animal_type}.")
        print(f"My {animal_type}'s name is {pet_name.title()}.")
    
    describe_pet('hamster', 'harry')
    
    I have a hamster.
    My hamster's name is Harry.
    

8.2.2 关键字实参

  • 关键字实参是传递给函数的名称值对。因为直接在实参中将名称和值关联起来,所以向函数传递实参时不会混淆。关键字实参无须考虑函数调用中的实参顺序,还清楚地指出了函数调用中各个值的用途
    def describe_pet(animal_type, pet_name):
        """显示宠物的信息"""
        print(f"\nI have a {animal_type}.")
        print(f"My {animal_type}'s name is {pet_name.title()}.")
    
    # 明确地指出了各个实参对应的形参
    # 关键字实参的顺序无关紧要,因为 Python 知道各个值该赋给哪个形参
    describe_pet(animal_type = 'hamster', pet_name = 'harry')
    
    I have a hamster.
    My hamster's name is Harry.
    

8.2.3 默认值

  • 编写函数时,可给每个形参指定默认值。在调用函数中给形参提供了实参时,Python 将使用指定的实参值;否则,将使用形参的默认值。因此,给形参指定默认值后,可在函数调用中省略相应的实参 (给形参指定默认值时,等号两边不要有空格)
    # 将形参 animal_type 设置默认值为'dog'
    def describe_pet(pet_name, animal_type='dog'):
    """显示宠物的信息。"""
    print(f"\nI have a {animal_type}.")
    print(f"My {animal_type}'s name is {pet_name.title()}.")
    
    describe_pet(pet_name = 'willie')
    # 由于显式地给 animal_type 提供了实参,Python 将忽略这个形参的默认值
    # describe_pet(pet_name='harry', animal_type='hamster')
    
    I have a dog.
    My dog's name is Willie.
    

8.3 返回值

  • 函数并非总是直接显示输出,它还可以处理一些数据,并返回一个或一组值。函数返回的值称为返回值。在函数中,可使用 return 语句将值返回到调用函数的代码行

8.3.1 返回简单值

  • 下面来看一个函数,它接受名和姓并返回整洁的姓名
    def get_formatted_name(first_name, last_name):
        """返回整洁的姓名"""
        full_name = f"{first_name} {last_name}"
        return full_name.title()
    
    # 提供一个变量,以便将返回的值赋给它
    musician = get_formatted_name('jimi', 'hendrix')
    print(musician)
    
    Jimi Hendrix
    

8.3.2 让实参变成可选的

  • 有时候,需要让实参变成可选的,这样使用函数的人就能只在必要时提供额外的信息。可使用默认值来让实参变成可选的
    # 为了让中间名变成可选的,可给形参 middle_name 指定一个空的默认值
    # 并在用户没有提供中间名时不使用这个形参
    def get_formatted_name(first_name, last_name, middle_name=''):
        if middle_name:
            full_name = f"{first_name} {middle_name} {last_name}"
        else:
            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')
    print(musician)
    
    Jimi Hendrix
    John Lee Hooker
    

8.3.3 返回字典

  • 函数可返回任何类型的值,包括列表和字典等较复杂的数据结构。例如,下面的函数接受姓名的组成部分,并返回一个表示人的字典
    # 可将 None 视为占位值
    def build_person(first_name, last_name, age=None):
        """返回一个字典,其中包含有关一个人的信息"""
        person = {'first': first_name, 'last': last_name}
        if age:
            person['age'] = age
        return person
    
    musician = build_person('jimi', 'hendrix', age = 27)
    print(musician)
    
    {'first': 'jimi', 'last': 'hendrix', 'age': 27}
    

8.3.4 结合使用函数和 while 循环

def get_formatted_name(first_name, last_name):
    full_name = f"{first_name} {last_name}"
    return full_name.title()

# 这是一个无限循环!
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}!")
Please tell me your name:
(enter 'q' at any time to quit)
First name: Tom
Last name: Bun

Hello, Tom Bun!
...

8.4 传递列表

  • 假设有一个用户列表,要问候其中的每位用户。下面的示例将包含名字的列表传递给一个名为 greet_users() 的函数,这个函数问候列表中的每个人
    def greet_users(names):
        """向列表中的每位用户发出简单的问候"""
        for name in names:
            msg = f"Hello, {name.title()}!"
            print(msg)
    
    usernames = ['hannah', 'ty', 'margot']
    greet_users(usernames)
    
    Hello, Hannah!
    Hello, Ty!
    Hello, Margot!
    

8.4.1 在函数中修改列表

  • 将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表所做的任何修改都是永久的
    • 来看一家为用户提交的设计制作 3D 打印模型的公司。需要打印的设计存储在一个列表中,打印后将移到另一个列表中
    # 包含两个形参:一个需要打印的设计列表和一个打印好的模型列表
    def print_models(unprinted_designs, completed_models):
        # 模拟打印每个设计,直到没有未打印的设计为止
        # 打印每个设计后,都将其移到列表 completed_models 中
        while unprinted_designs:
            current_design = unprinted_designs.pop()
            print(f"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 = ['phone case', 'robot pendant', 'dodecahedron']
    completed_models = []
    
    print_models(unprinted_designs, completed_models)
    show_completed_models(completed_models)
    
    Printing model: dodecahedron
    Printing model: robot pendant
    Printing model: phone case
    
    The following models have been printed:
    dodecahedron
    robot pendant
    phone case
    

编写函数时,如果发现它执行的任务太多,请尝试将这些代码划分到两个函数中。总是可以在一个函数中调用另一个函数,这有助于将复杂的任务划分成一系列步骤

8.4.2 禁止函数修改列表

  • 假设即便打印好了所有设计,也要保留原来的未打印的设计列表,以供备案。但由于将所有的设计都移出了 unprinted_designs,这个列表变成了空的
    • 为解决这个问题,可向函数传递列表的副本而非原件。这样,函数所做的任何修改都只影响副本,而原件丝毫不受影响,要将列表的副本传递给函数,可以像下面这样做
    # 切片表示法[:] 创建列表的副本
    function_name(list_name_[:])
    
    # 在 8.4.1 中,如果不想清空未打印的设计列表,可像下面这样调用 print_models()
    print_models(unprinted_designs[:], completed_models)
    

8.5 传递任意数量的实参

  • 预先不知道函数需要接受多少个实参,Python 允许函数从调用语句中收集任意数量的实参
  • 来看一个制作比萨的函数,它需要接受很多配料,但无法预先确定顾客要多少种配料。下面的函数只有一个形参 *toppings ,但不管调用语句提供了多少实参,这个形参会将它们统统收入囊中
    # 形参名 *toppings 中的星号让 Python 创建一个名为 toppings 的空元组
    # 并将收到的所有值都封装到这个元组中
    def make_pizza(*toppings):
        print("\nMaking a pizza with the following toppings:")
        for topping in toppings:
            print(f"- {topping}")
    
    # 不管收到一个值还是三个值,这个函数都能妥善处理   
    make_pizza('pepperoni')
    make_pizza('mushrooms', 'green peppers', 'extra cheese')
    
    Making a pizza with the following toppings:
    - pepperoni
    
    Making a pizza with the following toppings:
    - mushrooms
    - green peppers
    - extra cheese
    

8.5.1 结合使用位置实参和任意数量实参

  • 如果要让函数接受不同类型的实参,必须在函数定义中将接纳任意数量实参的形参放在最后。Python 先匹配位置实参和关键字实参,再将余下的实参都收集到最后一个形参中
    def make_pizza(size, *toppings):
        print(f"\nMaking a {size}-inch pizza with the following toppings:")
        for topping in toppings:
            print(f"- {topping}")
    
    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
    
    Making a 16-inch pizza with the following toppings:
    - pepperoni
    
    Making a 12-inch pizza with the following toppings:
    - mushrooms
    - green peppers
    - extra cheese
    

经常会看到通用形参名 *args ,它也收集任意数量的位置实参

8.5.2 使用任意数量的关键字实参

  • 有时候,需要接受任意数量的实参,但预先不知道传递给函数的会是什么样的信息。在这种情况下,可将函数编写成能够接受任意数量的键值对:调用语句提供了多少就接受多少
    # 形参 **user_info 中的两个星号让 Python 创建一个名为 user_info 的空字典
    # 并将收到的所有名称值对都放到这个字典中
    def build_profile(first, last, **user_info):
        """创建一个字典,其中包含知道的有关用户的一切"""
        user_info['first_name'] = first
        user_info['last_name'] = last
        return user_info
    
    user_profile = build_profile('albert', 'einstein',
                                 location='princeton',
                                 field='physics')
    print(user_profile)
    
    {'location': 'princeton', 'field': 'physics', 'first_name': 'albert', 'last_name': 'einstein'}
    

8.6 将函数存储在模块中

  • 使用函数的优点之一是可将代码块与主程序分离。通过给函数指定描述性名称,可让主程序容易理解得多。还可以更进一步,将函数存储在称为模块的独立文件中,再将模块导入到主程序中
    • import 语句允许在当前运行的程序文件中使用模块中的代码

8.6.1 导入整个模块

  • 要让函数是可导入的,得先创建模块。模块是扩展名为 .py 的文件,包含要导入到程序中的代码
    # pizza.py
    def make_pizza(size, *toppings):
        print(f"\nMaking a {size}-inch pizza with the following toppings:")
        for topping in toppings:
            print(f"- {topping}")
    
    # making_pizzas.py(与 pizza.py 处于同一目录)
    # 该行代码让 Python 打开文件 pizza.py,并将其中的所有函数都复制到这个程序中
    import pizza
    
    # 要调用被导入模块中的函数,可指定被导入模块的名称 pizza 和函数名 make_pizza(),并用句点分隔
    pizza.make_pizza(16, 'pepperoni')
    pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
    

8.6.2 导入特定的函数

  • 还可以导入模块中的特定函数,这种导入方法的语法如下
    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, 'mushrooms', 'green peppers', 'extra cheese')
    

8.6.3 使用 as 给函数指定别名

  • 如果要导入函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的别名:函数的另一个名称,类似于外号。要给函数取这种特殊外号,需要在导入它时指定
    from pizza import make_pizza as mp
    mp(16, 'pepperoni')
    mp(12, 'mushrooms', 'green peppers', 'extra cheese')
    

8.6.4 使用 as 给模块指定别名

  • 还可以给模块指定别名。通过给模块指定简短的别名(如给模块 pizza 指定别名 p)
    import pizza as p
    p.make_pizza(16, 'pepperoni')
    p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
    

8.6.5 导入模块中的所有函数

  • 使用星号(* )运算符可让Python导入模块中的所有函数(最好不要采用这种导入方法
    • 如果模块中有函数的名称与当前项目中使用的名称相同,可能导致意想不到的结果
    • Python 可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有函数
    • 最佳的做法是:要么只导入需要使用的函数,要么导入整个模块并使用句点表示法
    from pizza import *
    
    make_pizza(16, 'pepperoni')
    make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
    

9. 类

9.1 创建和使用类

  • 使用类几乎可以模拟任何东西。下面来编写一个表示小狗的简单类 Dog ,它表示的不是特定的小狗,而是任何小狗
    • 在 Python 中,通常可认为首字母大写的名称(如 Dog)指的是类,而小写的名称(如 my_dog)指的是根据类创建的实例,类中的函数称为方法
    • __init__() 是一个特殊方法,每当根据 Dog 类创建新实例时 Python 都会自动运行它。在这个方法的名称中,开头和末尾各有两个下划线
    • self.age = age 像这样可通过实例访问的变量称为属性
    class Dog:
        # 其中形参 self 必不可少,而且必须位于其他形参的前面
        # Python 调用这个方法来创建 Dog 实例时,将自动传入实参 self
        def __init__(self, name, age):
            """初始化属性 name 和 age"""
            # 以 self 为前缀的变量可供类中的所有方法使用,可以通过类的任何实例来访问
            self.name = name
            self.age = age
        
        # 每个与实例相关联的方法调用都自动传递实参 self 
        # 它是一个指向实例本身的引用,让实例能够访问类中的属性和方法
        def sit(self):
            """模拟小狗收到命令时蹲下"""
            print(f"{self.name} is now sitting.")
    
        def roll_over(self):
            """模拟小狗收到命令时打滚"""
            print(f"{self.name} rolled over!")
    
    # 创建表示特定小狗的实例
    my_dog = Dog('Willie', 6)
    your_dog = Dog('Lucy', 3)
    
    print(f"My dog's name is {my_dog.name}.")  # 要访问实例的属性,可使用句点表示法
    print(f"My dog is {my_dog.age} years old.")
    
    # 根据 Dog 类创建实例后,就能使用句点表示法来调用 Dog 类中定义的任何方法
    my_dog.sit()
    my_dog.roll_over()
    
    My dog's name is Willie.
    My dog is 6 years old.
    Willie is now sitting.
    Willie rolled over!
    

9.2 使用类和实例

  • 下面来编写一个表示汽车的类。它存储了有关汽车的信息,还有一个汇总这些信息的方法
    class Car:
        def __init__(self, make, model, year):
            """初始化描述汽车的属性"""
            self.make = make
            self.model = model
            self.year = year
            # 创建实例时,有些属性无须通过形参来定义,可在方法 __init__() 中为其指定默认值
            self.odometer_reading = 0
            
        def get_descriptive_name(self):
            """返回整洁的描述性信息"""
            long_name = f"{self.year} {self.make} {self.model}"
            return long_name.title()
    
        def read_odometer(self):
            """打印一条指出汽车里程的消息"""
            print(f"This car has {self.odometer_reading} miles on it.")
    
        # 这个方法接受一个里程值,并将其赋给 self.odometer_reading
        def update_odometer(self, mileage):
            """将里程表读数设置为指定的值,禁止将里程表读数往回调"""
            if mileage >= self.odometer_reading:
                self.odometer_reading = mileage
            else:
                print("You can't roll back an odometer!")
    
        # 将属性值递增特定的量,而不是将其设置为全新的值
        def increment_odometer(self, miles):
            """将里程表读数增加指定的量"""
            self.odometer_reading += miles
        
    # 根据 Car 类创建了一个实例
    my_used_car = Car('subaru', 'outback', 2015)
    print(my_used_car.get_descriptive_name())
    
    my_used_car.update_odometer(23_500)
    my_used_car.read_odometer()
    
    my_used_car.increment_odometer(100)
    my_used_car.read_odometer()
    
    2015 Subaru Outback
    This car has 23500 miles on it.
    This car has 23600 miles on it.
    

9.3 继承

  • 如果要编写的类是另一个现成类的特殊版本,可使用继承
    • 一个类继承另一个类时,将自动获得另一个类的所有属性和方法
    • 原有的类称为父类 ,而新类称为子类
    • 子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法
    • 对于父类的方法,只要它不符合子类模拟的实物的行为,都可以进行重写:可在子类中定义一个与要重写的父类方法同名的方法。这样,Python 将不会考虑这个父类方法,而只关注在子类中定义的相应方法
    class Car:
        # 在既有类的基础上编写新类时,通常要调用父类的方法 __init__() 
        # 这将初始化在父类 __init__() 方法中定义的所有属性,从而让子类包含这些属性
        def __init__(self, make, model, year):
            self.make = make
            self.model = model
            self.year = year
            self.odometer_reading = 0
            
        def get_descriptive_name(self):
            long_name = f"{self.year} {self.make} {self.model}"
            return long_name.title()
        
        def read_odometer(self):
            print(f"This car has {self.odometer_reading} miles on it.")
            
        def update_odometer(self, mileage):
            if mileage >= self.odometer_reading:
                self.odometer_reading = mileage
            else:
                print("You can't roll back an odometer!")
        
        def increment_odometer(self, miles):
            self.odometer_reading += miles
    
    class Battery:
        def __init__(self, battery_size=75):
            """初始化电瓶的属性"""
            self.battery_size = battery_size
    
        def describe_battery(self):
            """打印一条描述电瓶容量的消息"""
            print(f"This car has a {self.battery_size}-kWh battery.")
    
        def get_range(self):
            """打印一条消息,指出电瓶的续航里程"""
            if self.battery_size == 75:
                range = 260
            elif self.battery_size == 100:
                range = 315
                
            print(f"This car can go about {range} miles on a full charge.")
    
    # 电动汽车是一种特殊的汽车,因此可在前面创建的 Car 类的基础上创建新类 ElectricCar
    # 定义子类时,必须在圆括号内指定父类的名称
    class ElectricCar(Car):
        """电动汽车的独特之处"""
        def __init__(self, make, model, year):
            """先初始化父类的属性,再初始化电动汽车特有的属性"""
            # 这行代码让 Python 调用 Car 类的方法 __init__()
            # 父类也称为超类(superclass),名称 super 由此而来
            super().__init__(make, model, year)
            self.battery = Battery()
    
        def describe_battery(self):
            """打印一条描述电瓶容量的消息"""
            print(f"This car has a {self.battery_size}-kWh battery.")
    
    my_tesla = ElectricCar('tesla', 'model s', 2019)
    print(my_tesla.get_descriptive_name())
    my_tesla.battery.describe_battery()
    my_tesla.battery.get_range()
    
    2019 Tesla Model S
    This car has a 75-kWh battery.
    This car can go about 260 miles on a full charge.
    

9.4 导入类

  • 随着不断给类添加功能,文件可能变得很长,即便妥善地使用了继承亦如此。Python 在这方面提供了帮助,允许将类存储在模块中,然后在主程序中导入所需的模块

9.4.1 导入单个类

  • 将 Car 类存储在一个名为 car.py 的模块中,从现在开始,使用该模块的程序都必须使用更具体的文件名,如 my_car.py
    # car.py
    class Car:
        ...
    
    # my_car.py
    from car import Car
    
    my_new_car = Car('audi', 'a4', 2019)
    print(my_new_car.get_descriptive_name())
    ...
    

9.4.2 在一个模块中存储多个类

# car.py
class Car:
    ...
class Battery:
    ...
class ElectricCar(Car):
    ...
# my_electric_car.py
from car import ElectricCar

my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
...

9.4.3 从一个模块中导入多个类

  • 可根据需要在程序文件中导入任意数量的类。如果要在同一个程序中创建普通汽车和电动汽车,就需要将 Car 类和 ElectricCar 类都导入
    # my_cars.py
    from car import Car, ElectricCar
    
    my_beetle = Car('volkswagen', 'beetle', 2019)
    print(my_beetle.get_descriptive_name())
    
    my_tesla = ElectricCar('tesla', 'roadster', 2019)
    print(my_tesla.get_descriptive_name())
    

9.4.4 导入整个模块

# my_cars.py
import car

my_beetle = car.Car('volkswagen', 'beetle', 2019)
print(my_beetle.get_descriptive_name())

my_tesla = car.ElectricCar('tesla', 'roadster', 2019)
print(my_tesla.get_descriptive_name())

9.4.5 使用别名

  • 例如,要在程序中创建大量电动汽车实例,需要反复输入 ElectricCar ,非常烦琐。为避免这种烦恼,可在 import 语句中给 ElectricCar 指定一个别名
    from electric_car import ElectricCar as EC
    
    my_tesla = EC('tesla', 'roadster', 2019)  # 使用别名
    

9.5 Python 标准库

  • Python标 准库是一组模块,可以使用标准库中的任何函数和类,只需在程序开头包含一条简单的 import 语句即可。下面来看看模块 random
    • 在这个模块中,一个有趣的函数是 randint()。它将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数,下面演示了生成一个位于 1~6 之间的随机整数
    from random import randint
    
    print(randint(1, 6))
    
    1
    
    • 在模块 random 中,另一个有用的函数是 choice()。它将一个列表或元组作为参数,并随机返回其中的一个元素
    from random import choice
    players = ['charles', 'martina', 'michael', 'florence', 'eli']
    first_up = choice(players)
    
    print(first_up)
    
    michael
    

10. 文件和异常

10.1 从文件中读取数据

10.1.1 读取整个文件

  • 要读取文件,需要一个包含几行文本的文件。下面首先创建一个文件,它包含精确到小数点后 30 位的圆周率值,且在小数点后每 10 位处换行
    # pi_digits.txt
    3.1415926535
      8979323846
      2643383279
    
    # 函数 open() 接受一个参数:要打开的文件的名称
    # 关键字 with 在不再需要访问文件后将其关闭
    with open('pi_digits.txt') as file_object:
        # 使用方法 read() 读取这个文件的全部内容
        contents = file_object.read()
    
    # Python 方法 rstrip() 删除字符串末尾的空白
    print(contents.rstrip())
    
    3.1415926535
      8979323846
      2643383279
    

10.1.2 文件路径

# 到文件夹 python_work 下的文件夹 text_files 中去查找指定的 .txt 文件
with open('text_files/filename.txt') as file_object:

# 还可以将文件在计算机中的准确位置告诉 Python
# 这样就不用关心当前运行的程序存储在什么地方了,这称为绝对文件路径
file_path = '/home/ehmatthes/other_files/text_files/_filename_.txt'
with open(file_path) as file_object:

10.1.3 创建一个包含文件各行内容的列表

  • 读取文件时,常常需要检查其中的每一行:可能要在文件中查找特定的信息,或者要以某种方式修改文件中的文本
  • 使用关键字 with 时,open() 返回的文件对象只在 with 代码块内可用
    • 如果要在 with 代码块外访问文件的内容,可在 with 代码块内将文件的各行存储在一个列表中,并在 with 代码块外使用该列表
    filename = 'pi_digits.txt'
    
    with open(filename) as file_object:
        # 方法 readlines() 从文件中读取每一行,并将其存储在一个列表中
        lines = file_object.readlines()
    
    # 列表 lines 的每个元素都对应于文件中的一行
    for line in lines:
        print(line.rstrip())
    
    3.1415926535
      8979323846
      2643383279
    

10.1.4 使用文件的内容

  • 将文件读取到内存中后,就能以任何方式使用这些数据了。下面以简单的方式使用圆周率的值。首先,创建一个字符串,它包含文件中存储的所有数字,且没有任何空格
  • 读取文本文件时,Python 将其中的所有文本都解读为字符串。如果读取的是数,并要将其作为数值使用,就必须使用函数 int() 将其转换为整数或使用函数 float() 将其转换为浮点数
    filename = 'chapter_10/pi_digits.txt'
    
    with open(filename) as file_object:
        lines = file_object.readlines()
    
    pi_string = ''
    for line in lines:
        pi_string += line.strip()
    
    print(pi_string)
    print(len(pi_string))
    
    3.141592653589793238462643383279
    32
    

10.2 写入文件

  • 保存数据的最简单的方式之一是将其写入文件中。通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在

10.2.1 写入空文件

  • 要将文本写入文件,在调用 open() 时需要提供另一个实参,告诉 Python 要写入打开的文件
  • 打开文件时,可指定读取模式(‘r’)、写入模式(‘w’)、附加模式(‘a’)或读写模式(‘r+’)。如果省略了模式实参,Python 将以默认的只读模式打开文件
  • 如果要写入的文件不存在,函数 open() 将自动创建它。然而,以写入模式(‘w’)打开文件时千万要小心,因为如果指定的文件已经存在,Python 将在返回文件对象前清空该文件的内容
    filename = 'programming.txt'
    
    # 第一个实参也是要打开的文件的名称
    # 第二个实参('w')表示要以写入模式打开这个文件
    with open(filename, 'w') as file_object:
        file_object.write("I love programming.")
    
    # programming.txt
    I love programming.
    

10.2.2 附加到文件

  • 如果要给文件添加内容,而不是覆盖原有的内容,可以以附加模式打开文件。以附加模式打开文件时,Python 不会在返回文件对象前清空文件的内容,而是将写入文件的行添加到文件末尾
    filename = 'programming.txt'
    
    with open(filename, 'a') as file_object:
        file_object.write("I also love finding meaning in large datasets.\n")
        file_object.write("I love creating apps that can run in a browser.\n")
    
    # programming.txt
    I love programming.
    I also love finding meaning in large datasets.
    I love creating apps that can run in a browser.
    

10.3 异常

  • Python 使用称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让 Python 不知所措的错误时,它都会创建一个异常对象
  • 异常是使用 try-except 代码块处理的。try-except 代码块让 Python 执行指定的操作,同时告诉 Python 发生异常时怎么办

10.3.1 处理 ZeroDivisionError 异常

  • 可能知道,不能用数除以 0,但还是让 Python 这样做
    print(5 / 0)
    
    Traceback (most recent call last):
      File "division_calculator.py", line 1, in <module>
        print(5/0)
    ZeroDivisionError: division by zero
    

10.3.2 使用 try-except 代码块

  • 当认为可能会发生错误时,可编写一个 try-except 代码块来处理可能引发的异常
  • 如果 try-except 代码块后面还有其他代码,程序将接着运行,因为已经告诉了 Python 如何处理这种错误
    try:
        print(5/0)
    except ZeroDivisionError:
        print("You can't divide by zero!")
    
    You can't divide by zero!
    

10.3.3 使用异常避免崩溃

  • try-except-else 代码块的工作原理:Python 尝试执行 try 代码块中的代码,只有可能引发异常的代码才需要放在try 语句中。有时候,有一些仅在 try 代码块成功执行时才需要运行的代码,这些代码应放在 else 代码块中
    print("Give me two numbers, and I'll divide them.")
    print("Enter 'q' to quit.")
    
    while True:
        first_number = input("\nFirst number: ")
        if first_number == 'q':
            break
        second_number = input("Second number: ")
        if second_number == 'q':
            break
        try:
            answer = int(first_number) / int(second_number)
        except ZeroDivisionError:
            print("You can't divide by 0!")
        else:
            print(answer)
    
    Give me two numbers, and I'll divide them.
    Enter 'q' to quit.
    
    First number: 2
    Second number: 6
    0.3333333333333333
    
    First number: q
    
    Process finished with exit code 0
    

10.3.4 处理 FileNotFoundError 异常

  • 使用文件时,一种常见的问题是找不到文件:查找的文件可能在其他地方,文件名可能不正确,或者这个文件根本就不存在
    filename = 'alice.txt'
    
    try:
        with open(filename, encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        print(f"Sorry, the file {filename} does not exist.")
    else:
        # Count the approximate number of words in the file.
        words = contents.split()
        num_words = len(words)
        print(f"The file {filename} has about {num_words} words.")
    
    Sorry, the file alice.txt does not exist.
    # The file alice.txt has about 29465 words.
    

10.3.5 分析文本

  • 使用方法 split(),它能根据一个字符串创建一个单词列表 (参见 10.3.4)
    title = "Alice in Wonderland"
    
    print(title.split())
    
    ['Alice', 'in', 'Wonderland']
    

10.3.6 静默失败

  • 但并非每次捕获到异常都需要告诉用户,有时候你希望程序在发生异常时保持静默,就像什么都没有发生一样继续运行。可使用 pass 语句实现
def count_words(filename):
    """计算一个文件大致包含多少个单词"""
    try:
        with open(filename, encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        # pass 语句还充当了占位符,提醒在程序的某个地方什么都没做,并且以后也许要在这里做什么
        pass
    else:
        words = contents.split()
        num_words = len(words)
        print(f"The file {filename} has about {num_words} words.")

filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
    count_words(filename)
The file alice.txt has about 29465 words.
The file siddhartha.txt has about 42172 words.
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.

10.4 存储数据

  • 模块 json 能够将简单的 Python 数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。还可以使用 json 在 Python 程序之间分享数据
    • JSON(JavaScript Object Notation)格式最初是为 JavaScript 开发的,但随后成了一种常见格式,被包括 Python 在内的众多语言采用

10.4.1 使用 json.dump() 和 json.load()

  • 编写一个存储一组数的简短程序,再编写一个将这些数读取到内存中的程序。第一个程序将使用 json.dump() 来存储这组数,而第二个程序将使用 json.load()
    import json
    
    numbers = [2, 3, 5, 7, 11, 13]
    
    filename = 'numbers.json'
    with open(filename, 'w') as f:
        # 使用函数 json.dump() 将数字列表存储到文件 numbers.json 中
        json.dump(numbers, f)
    
    # numbers.json
    [2, 3, 5, 7, 11, 13]
    
    import json
    
    filename = 'numbers.json'
    with open(filename) as f:
        # 使用函数 json.load() 加载存储在 numbers.json 中的信息
        numbers = json.load(f)
        
    print(numbers)
    
    [2, 3, 5, 7, 11, 13]
    

10.4.2 重构

  • 经常会遇到这样的情况:代码能够正确地运行,但通过将其划分为一系列完成具体工作的函数,还可以改进,这样的过程称为重构。重构让代码更清晰、更易于理解、更容易扩展
    import json
    
    def get_stored_username():
        """如果存储了用户名,就获取它"""
        filename = 'username.json'
        try:
            with open(filename) as f:
                username = json.load(f)
        except FileNotFoundError:
            return None
        else:
            return username
    
    def get_new_username():
        """提示用户输入用户名"""
        username = input("What is your name? ")
        filename = 'username.json'
        with open(filename, 'w') as f:
            json.dump(username, f)
        return username
    
    def greet_user():
        """问候用户,并指出其名字"""
        username = get_stored_username()
        if username:
            print(f"Welcome back, {username}!")
        else:
            username = get_new_username()
            print(f"We'll remember you when you come back, {username}!")
    
    greet_user()
    
    Welcome back, eric!
    

你可能感兴趣的:(Python入门学习,python,开发语言,学习,笔记,算法)