《Python编程从入门到实践》学习笔记

目录

第二章 变量和简单数据类型

第三章 列表简介

第四章  操作列表

第五章  if语句

第六章  字典

第七章  用户输入和 while 循环

第八章  函数

第九章  类

第十章    文件和异常

第十一章  测试代码


第二章 变量和简单数据类型

1.Python始终记录变量的最新值

2.变量的命名和使用

     (1)变量名只能包含字母、下划线、和数字,数字不能作为变量名的开头

     (2)变量名不能包含空格

     (3)不能将Python关键字和函数名用作变量名

3.变量定义:变量是可以赋给值的标签,也可以说变量指向特定的值

4.用引号括起的都是字符串,其中的引号可以是单引号也可以是双引号

5.(1)方法title()首字母大写的方式显示每个单词;

   (2)方法upper()输出字母全为大写;

    (3)方法lower()输出字母全为小写。不影响原变量的值 

6.f字符串:f是format(设置格式)的简写,可以用来在字符串中使用变量的值。例:print(f"hello!,{变量名}"→hello!,变量值

7.都知道的,\n是换行符,\t是制表符。

8.(1) lstrip()删除字符串开头的空白;

   (2)rstrip()删除字符串末尾的空白;

   (3)strip()删除字符串两边的空白,

      注意:不过这三种删除都是暂时的,下一次调用变量时依然包含空白,除非改变变量的值的 空白,才能实现永久删除空白

 9.整数运算:加(+)减(-)乘(*)除(/),乘方(**)。例:3**2=9

10.表示很大的数时,可以使用下划线将其中数字分组,使其更清晰易读,python打印时不会打印下划线

11.可以同时给多个变量赋值,需要用逗号将变量名分开,要赋给的值同样处理。

12.常量类似变量,一般使用字母全大写(可以包含数字、下划线)的变量名来指出某个变量是常量。

13.编写注释,用井号(#)标识,井号后面的内容会被解释器忽略。

第三章 列表简介

1.在python中,用方括([ ])号表示列表,并用逗号分隔其中的元素。

2.在python中,第一个列表元素的索引是0,访问列表的任何元素,都可将其位置减1。

3.python为访问最后一个列表元素提供了一种特殊语法,索引-1返回列表最后一个元素,索引-2返回列表倒数第二个元素,以此类推。

4.修改列表元素,可指定列表名和要修改的元素的索引,在指定该元素的新值。例:列表名[索引]='新值'

5(1).方法append()将元素添加到列表末尾,例:列表名.append('新元素')

   (2)方法insert()可将元素添加到列表任何位置,需指定新元素的索引和值。例:列表名.insert(索引,'新元素')

6.(1)del语句删除任意位置的列表元素,需指定索引,永久删除。例:del  列表名[索引]

    (2)方法pop()删除列表任意位置元素,需指定索引(若不指定索引,则会删除列表最后一个元素),被删除的元素我们仍有办法调用该元素。例:popped_列表名=列表名.pop(索引)

                                         print(popped_列表名)→输出的值即为被删除的元素

    (3)方法remove()根据元素值删除列表元素,例:列表名.remove('元素的值')

       使用方法remove()删除列表元素,也可以接着使用它的值,方法同(2),需注意的是,方法remove()只删除第一个 指定的值,如果需要删除的值可能在列表中出现多次,就需要使用循环来确保将每个值都删除。

7.如果你要从列表中删除一个元素,且不再以任何方式使用它,就使用del语句;如果你要在删除元素后还能继续使用它,就使 用方法pop()

8.(1)方法sort()将列表中元素按字母顺序排列(永久排序)。

             方法sort(reverse=True)将列表中元素按与字母排列相反的顺序排列(永久排序)。

    (2)函数sorted()对列表暂时排列,同样的有函数sort(reverse=True)

    (3)方法reverse()反转列表元素的排列顺序,永久性的改变列表元素的排列顺序,但只需                  重 新调用一下方法reverse() 就可以恢复到原来的排序

9.函数len()可快速获悉列表长度。

第四章  操作列表

1.在for循环代码行后面应加冒号(:),下面每个缩进的代码行都是循环的一部分。在for循环后        面没有缩进的代码行只执行一次。(python根据缩进来判断代码行与前一个代码行的关系)

2.(1)函数range()配合for循环生成一系列数,需注意,函数range()让python从指定的第一个值开始数,并在到达指定的第二个值前停止。因为他在第二个值前停止,故输出不包含第二个值,

   例如:for value in range(1,5):

              (注意这里须有缩进)print(value)→输出1~4,而不是1~5,这是编程语言中常见的差                                                                               一行为

(2)函数range()也可指定步长,例:range(初始值,终止值,步长)

(3)调用range()函数时,也可指指定一个参数,这样他将从0开始。例:range(6)返回0~5

3.可使用函数list()配合函数range()创建数字列表。

    例:numbers=list(range(1,6))

            print(numbers)→[1,2,3,4,5]

4.对数字列表执行简单统计 计算:

(1)函数min(数字列表名)→最小值

(2)函数max(数字列表名)→最大值                      

(3)函数sum(数字列表名)→总和

5.列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素。

例:cobes=[value**3 for value in range(1,11)]

print(cobes)→[1,8,27,64,125,216,343,512,729,1000]

即:列表名=[与值相关的表达式    for   值   in   range()]

6.处理列表部分元素,python成为切片,要创建切片,需指定要使用的第一个元素的索引到最后一个元素的索引,同函数range()一样,python在到达第二个索引之前的元素后停止。例:

print(列表名[0:3])→输出索引为0,1,2的元素组成的列表

print(列表名[2:])→输出索引为从2开始到终止的所有元素组成的列表

print(列表名[:3])→输出索引为从0开始到3的所有元素组成的列表

print(列表名[:])→输出索引为从0开始到终止的所有元素组成的列表

7.python将不能修改的值称为不可变的,而不可变的列表称为元组,元组看起来很像列表,但使用圆括号而非中括号来标识。

      严格来说,元组是由逗号标识的,圆括号只是让元组看起来更整洁、更清晰。如果你要定义只包含一个元素的元组,必须在这个元素后面加上逗号:例:my_t=(3,)

      创建只包含一个元素的元组通常没有意义,但自动生成的元组有可能只有一个元素。

8.虽然不能修改元组的元素,但可以给存储元组的变量赋值。首先定义一个元组,并将其中存储的值打印出来,接下来,将一个新元组关联到原来的元组名上,就可以打印新的存储的值。

9.元组是比列表更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,就可以选择元组。

10.(1)PEP8 建议每级缩进使用四个空格;

     (2)在字处理文档中,使用制表符而不是空格来缩进(注意:在程序中混合使用制表符和空格可            能导致极难排查的问题);

     (3)建议每行不要超过80字符;

     (4)要将程序的不同部分分开,建议使用空格

第五章  if语句

1.每条 if 语句的核心都是一个值为 True 或 False 的表达式,这种表达式称为条件测试。

2.(1)判断相等运算符:==;

(2)判断不相等运算符:!=;

(3)同理还有数值比较的大于、小于、小于等于、大于等于;

(4)使用关键字 and 检查多个条件,与关系;

(5)使用关键字 or 检查多个条件,或关系;

(6)使用关键字 in 判断特定的值是否已包含在列表中;

(7)使用关键字 not in 判断特定的值是否不包含在列表中。

3.同条件表达式一样,布尔表达式的结果要么是True 要么是Flase 布尔值通常用来记录条件。

在跟踪程序状态或程序中重要的条件方面,布尔值提供了一种高效的方式。例:

4.(1)最简单的 if 语句只有一个测试

游戏是否正在运行,或者用户是否可以编辑网站的特定内容:

       game_active =True   

       can_edit=Flase     

和一个操作,在 if 语句中缩进的作用与在 for 循环中相同。

(2) if-else 语句,在条件通过是执行一个操作,在没有通过是执行另一个操作。

(3) if-elif-else 结构,检查超过两个的情形,可根据需要使用任意数量的 elif 代码块。

(4) if-elif 结构(省略 else 代码块),else是一条包罗万象的语句,只要不满足任何 if 或 elif 中            的条件测试,其中代码就会执行,这可引入恶意或无效的数据,如果我们知道最终的测试条            件,可考虑使用一个 elif 代码块来代替 else 代码块。

(5)一系列独立不含有 elif 和 else 的 if 语句,可执行多个代码块; if-elif-else 结构功能强大,但           仅适用于只有一个条件满足的情况,仅执行一个代码块。

5. PEP8 建议,在诸如 ==、>= 和 <= 等比较运算符两边各添加一个空格;我建议在and、or这种       表示与或关系的两边的条件都用圆括号括起来。

第六章  字典

1. 字典是一系列键值对。每个键都与一个值相连,你可使用键来访问相关联的值。与键相关联的         值 可以是数、字符串、列表乃至字典。

2.字典用放在花括号({})中的一系列键值对表示。键值对是两个相关联的值,指定键时,python     将返回与之相关联的值。键和值之间用冒号分隔,而键值对之间用逗号分隔。在字典中,想储存      多少键值对都可以。例:字典名={'键1':'值1','键2':'值2'}

3. 要获取与键相关联的值,可依次指定字典名和放在方括号内的键。例:print(字典名['键1'])→     值1

4. 在字典中添加键值对,可以次指定字典名、用方括号括起的键和相关联的值。例:字典名['键3']='值3'

5. 字典中元素排列顺序与定义是相同,元素的排列顺序与添加时相同。

6. 使用字典来存储用户提供的数据或在编写能自动生成大量键值对的代码时,通常需要先定义一个空字典。

7.修改字典中的值,可依次指定字典名、用方括号括起的键,以及与该键相关联的新值。例:字典名['键1']='新值1'

8. 删除字典中不需要的键值对,可使用 del 语句,需指定字典名和要删除的键(永久删除)。例:del  字典名['键1']

9.当我们需要使用多行来定义字典时,要在输入左花括号后,在下一行缩进四个空格,指定第一个键值对,并在它后面加上一个逗号,此后,按回车键,文本编辑器将自动缩进后续键值对,且缩进量与第一个键值对相同。定义好字典后,在最后一个键值对的下一行添加一个右花括号,并缩进四个空格。

10.方法 get (参数1,参数2)用来访问值,它的第一个参数用于指定键,是必不可少的;第二个参数为指定的键不存在时要返回的值,是可选的。如果没有指定第二个参数且指定的键不存在,python 将返回值  None  。这个特殊值表示没有相应的值。None  并非错误,而是一个表示所需值不存在的特殊值。

11. 如果存在指定的键有不存在的可能,应该考虑使用方法 get (),而不要使用方括号表示法。

12.使用 for 语句和方法 items () 遍历字典。返回一个键值对列表。要编写遍历字典的 for 循环,可声明两个变量,分别用于存储键值对中的键和值,这两个变量可使用任意名称。例:for  变量1,变量2   in  字典名.items():

13. 使用  keys()遍历字典中的所有键,例:for  变量  in  字典名.keys ():

      key()可省略,不影响输出,例:for  变量  in  字典名:

      方法  key() 并非只能遍历,实际上,它返回一个列表,其中包含字典中的所有键。

14.按特定顺序遍历字典中的所有键:

(1)在 for 循环中对返回的键进行排序;

(2)使用函数  sorted()来获得按特定顺序排列的键列表的副本。

15. 方法 values()来返回一个值列表。例:for  变量  in  字典名.values()

16. 集合 set()来剔除列表中的重复项。集合中的每个元素都必须是独一无二的。例:set (列表    名)

17. 可使用对花括号直接创建集合,并在其中用逗号分隔元素。例:集合名={'元素1','元素2'}

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

19. 有时候需要将一系列字典存储在列表中,或将列表作为值存储在字典中,称为嵌套。可以在列表中嵌套字典。在字典中嵌套列表甚至在字典中嵌套字典。注意:列表和字典的嵌套不宜太多。

第七章  用户输入和 while 循环

1. 函数 input()让程序暂停运行,等待用户输入一些文本,

2.使用函数 int()来获取数值输入

3.使用函数 input()输入的内容,python 视为字符,无法用于数值比较。可以再使用 int()数去该字符串,让 python 将输入视为数值。

4. 求模运算符:%   。它将两个数相除并返回余数。

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

6.在要求很多条件都满足才继续运行的程序中,可以定义一个变量,用于判断整个程序是否处于活动状态,这个变量称为标志。

7.使用 break 语句来控制程序流程。要立即退出 while 循环,不在运行循环中余下的代码。可使用 break 语句

8. 在 python 循环中都可使用 break 语句。例:可使用 break 语句来退出遍历列表或字典的 for 循环。

9. 使用 continue 语句可以返回循环开头,并根据条件测试结果决定是否继续执行循环。

10. 要避免出现无限循环,若出现。可按Ctrl + C,也可关闭显示程序输出的终端窗口。

11. for 循环是一种遍历列表的有效方式,但不应再 for 循环中修改列表,否则将导致 python 难以跟踪其中的元素。要在遍历列表的同时对其进行修改,可使用 while 循环。通过将 while 循环同列表和字典结合起来使用,可收集、存储并组织大量输入,供以后查看和显示。

第八章  函数

1. 使用关键字 def 定义函数,定义以冒号结尾

2. 调用函数,可依次指定函数名以及用圆括号括起的必要信息

3. python中的文本是称为文档字符串的注释,描述了函数是做什么的。文档字符串用三引号括起,python用他们来生成有关程序中函数的文档。

程序:

def greet_user():
    """显示简单的问候语"""
    print("Hello!")
greet_user()
====================== RESTART: E:/python3.9.2/greeter.py ======================
Hello!
>>> 

4.也可以通过在圆括号内添加一个变量,让函数接受你给这个变量的任何值。
程序:

def greet_user(username):
    """显示简单的问候语"""
    print(f"Hello!{username.title()}")
greet_user('jesse')
====================== RESTART: E:/python3.9.2/greeter.py ======================
Hello!Jesse
>>> 

5.如上段代码,函数 greet_user()的定义中,变量 username 是一个形参,即完成工作所需的信息,在代码 greet_user('jesse')中,值 'jesse' 是一个实参,即调用函数时传递给函数的信息。

6. 函数定义中可能包含多个形参,因此函数调用中也可能包含多个实参。

位置实参:要求实参的顺序与形参的顺序相同;

关键字实参:其中每个实参都有变量名和值组成,也可以使用列表和字典。

位置实参程序:

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('cat','mimi')
describe_pet('dog','dahuang')

====================== RESTART: E:/python3.9.2/greeter.py ======================

I have a cat
My cat's name is Mimi

I have a dog
My dog's name is Dahuang
>>> 

关键字实参程序:

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(animal_type='cat',pet_name='mimi')
describe_pet(pet_name='dahuang',animal_type='dog')

====================== RESTART: E:/python3.9.2/greeter.py ======================

I have a cat
My cat's name is Mimi

I have a dog
My dog's name is Dahuang
>>> 

7. 位置实参的顺序很重要,要确认函数调用中的实参与函数定义中形参的顺序一致;

关键字实参是传递给函数的名称值对,因为直接在实参中将名称和值联系起来,所以向函数传递实参是不会混淆,关键字实参的顺序无关紧要,因为 python 知道各个值该赋给哪个形参。

8.编写函数时,可以给每个形参指定默认值。在调用函数中给形参提供了实参时, python 将使用指定的实参,否则,将使用形参的默认值。

程序:

def describe_pet(animal_type,pet_name='lele'):
    """显示宠物信息"""
    print(f"\nI have a {animal_type}")
    print(f"My {animal_type}'s name is {pet_name.title()}")
describe_pet('cat','mimi')
describe_pet('dog')

====================== RESTART: E:/python3.9.2/greeter.py ======================

I have a cat
My cat's name is Mimi

I have a dog
My dog's name is Lele
>>> 

注意:使用默认值时,必须先在形参列表中列出没有默认值的形参,在列出有默认值的实参,这让 python 能够正确的解读位置实参。 

9. 返回值:函数返回的值。使用 return 语句将值返回到调用函数的代码行。

程序:

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)
=================== RESTART: E:/python3.9.2/formatted_name.py ==================
Jimi Hendrix
>>> 

10. 将某个实参变成可选的:可将该实参移到形参列表末尾并将其默认值设为空字符串。

程序:

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('jimi','hendrix','lee')
print(musician)
=================== RESTART: E:/python3.9.2/formatted_name.py ==================
Jimi Hendrix
Jimi Lee Hendrix
>>> 

11.函数可以返回任意值,包括列表和字典。

程序:

def get_formatted_name(first_name,last_name,age=None):
    """返回整洁的名字"""
    person={'first':first_name,'last':last_name}
    if age:
        person['age']=age
    return person
musician=get_formatted_name('jimi','hendrix',27)
print(musician)

=================== RESTART: E:/python3.9.2/formatted_name.py ==================
{'first': 'jimi', 'last': 'hendrix', 'age': 27}
>>> 

在上述函数定义中,新增了一个可选形参 age ,将其默认值设置为特殊值 None (表示变量没有值:输入零(0)、空字符串('')、None 都视为没有值)可将None视为占位值。在测试条件中,None 相当于 Flase 

12. 程序:

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)

=================== RESTART: E:/python3.9.2/formatted_name.py ==================
Printing model:dodecahedron
Printing model:robot pendant
Printing model:phone case

The following models have been printed:
dodecahedron
robot pendant
phone case
>>> 

相比于没有函数的程序,使用函数的程序更容易扩充和维护。每个函数都应只负责一项具体的工作。

13. 传递任意数量的实参。例:def   函数名(位置形参1,*形参2)

其中  *形参2  中的星号(*)让 python 创建一个名为 形参2  的空元组,python 先匹配位置实参和关键字实参,再将余下的所有实参都收集到这个元组里

14. 传递任意数量的关键字实参,例:def (形参1,**形参2)

其中  **形参2  中的两个星号(**)让 python 创建一个名为 形参2  的空字典,同上。

15. 使用函数可以将代码和主程序分离。通过给予描述性的名称,让主程序更加容易理解

更进一步,可以将函数存储在称为模块的独立文件中,再讲模块导入到主程序中。

16.  import 语句允许在当前运行的程序文件中使用模块中的代码。

(1)模块是扩展名为 .py 的文件,包含要导入到文件中的代码

例:

import   模块名                              #调用模块,这样就可以使用模块中的所有函数了

模块名.函数名1(相应实参)        #调用了该模块中的函数1

(2)导入特定函数:例:

from  模块名  import   函数名1,函数名2,函数名3

函数名1(相应实参)

可根据需要从模块中导入任意数量函数,用逗号分隔函数名,使用这种语法时,调用函数时无需任何句点。由于在 import 语句中显式地导入了函数,调用时就只需指定其名称即可。

(3)导入模块中的所有函数。例: from  模块名  import *

17. (1)使用 as 给函数指定别名。例:from  模块名  import   函数名  as   别名

      (2)使用 as 给模块指定别名。例:import   模块名    as    别名

18. (1)应给函数指定描述性名称,且只在其中使用小写字母和下划线。

(2)每个函数都应包含简要地阐述其功能的注释。该注释应采用文档字符串格式并紧跟在函数定义后面。

(3)函数定义由于形参很多导致长度过长,可在函数定义中输入左括号后按回车键,并在下一行按两次 Tab 键,从而将形参列表和只缩进一层的函数体区分开来。

(4)如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开。

(5)所有 import 语句都应放置在文件开头,除非在文件开头使用了注释来描述整个程序。

第九章  类

1.   面向对象编程是最有效的软件编写方法之一。根据类来创建对象称为实例化,这让你能够使用类的实例。使用类几乎可以模拟任何东西。你可以按需求根据一个类创建任意数量的实例。

2.  根据约定在 python 中,首字母大写的名称指的是类。这个类定义中没有圆括号,是因为要从空白创建这个类。小写的名称(例如下面程序中的实例 my_dog )指的是根据类创建的实例。

程序:

class Dog:
    """一次模拟小狗的简单尝试"""
    def __init__(self,name,age):
        """初始化属性name和age"""
        self.name=name                  #以 self 为前缀的变量可供类中的所有方法使用,可以通过                                                                类的任何实例来访问。像这样通过实例访问的变量称为属性。
        self.age=age

    def sit(self):                                       #这些方法执行时不需要额外的信息,因此他们只有一个形                                                                  参 self 
        """模拟小狗收到命令时下蹲"""
        print(f"{self.name} is now sitting.")

    def roll_over(self):
        """模拟小狗收到命令时打滚"""
        print(f"{self.name} rolled over")

my_dog = Dog('Willie',6)
my_dog.sit()
my_dog.roll_over()
print(f"My dog's name is {my_dog.name}")
print(f"My dog is {my_dog.age} years old.")

======================== RESTART: E:\python3.9.2\dog.py 
Willie is now sitting.
Willie rolled over
My dog's name is Willie
My dog is 6 years old.
>>> 

3. 类中的函数称为方法,前面学到的有关函数的一切都适用于方法,目前而言,唯一的重要差别是调用方法的方式。

4. 方法 __init__(self,形参1,形参2)是一个特殊的方法,在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免 python 默认方法与普通方法发生名称冲突。

在这个方法中形参 self 必不可少,而且必须位于其他形参的前面。

问:为什么必须在方法定义中包含形参 self ?

答:因为 python 调用这个方法来创建 Dog 实例时,将自动传入实参 self 。每个与实例相关联的方法调用都自动传入实参 self ,它是一个只想实力本身的引用,让实例能够访问类中的属性和方法。每当根据 Dog 类创建实例时,都只需给除形参 self 外的其他形参提供实参。

5. 创建实例时,有些属性无需通过形参来定义,可在方法 __init__()中为其指定默认值。

程序: 

class Car:
    """一次模拟汽车的简单尝试"""

    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.year}"
        return long_name.title()
    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it.")

my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23                                        #直接修改属性的值
my_new_car.read_odometer()
======================== RESTART: E:/python3.9.2/car.py ========================
2019 Audi 2019
This car has 23 miles on it.
>>> 

6.  修改属性的值:

(1)直接修改属性的值,如上例程序

(2)通过方法修改属性的值,

程序:

class Car:
    """一次模拟汽车的简单尝试"""

    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.year}"
        return long_name.title()
    
    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it.")

    def updata_odometer(self,mileage):
        """
        将里程表读数设置为指定的值
        禁止将里程表读数往回调
        """
        if mileage >= self.odometer_reading:
            self.odometer_reading = mileage
        else:
            print("You can't roll back an odometer")
        
my_new_car = Car('audi','a4',2019)
print(my_new_car.get_descriptive_name())
my_new_car.updata_odometer(23)                                       #通过方法修改属性的值
my_new_car.read_odometer()

 

======================== RESTART: E:/python3.9.2/car.py ========================
2019 Audi 2019
This car has 23 miles on it.
>>> 

(3) 通过方法对属性的值进行递增

程序:

class Car:
    """一次模拟汽车的简单尝试"""

    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.year}"
        return long_name.title()
    
    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it.")

    def updata_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
        
my_used_car = Car('subaru','outback',2015)
print(my_used_car.get_descriptive_name())

my_used_car.updata_odometer(23_500)
my_used_car.read_odometer()

my_used_car.increment_odometer(100)
my_used_car.read_odometer()

======================== RESTART: E:/python3.9.2/car.py ========================
2015 Subaru 2015
This car has 23500 miles on it.
This car has 23600 miles on it.
>>> 

7.  一个类继承另一个类时,将自动获得另一个类的所有属性和方法。原有的类称为父类(超类),而新的类称为子类。子类继承了父类的所有方法和属性,同时还可以定义自己的属性和方法。

8.  创建子类时,父类必须包含在当前文件中,且位于子类前面,定义子类时,必须在圆括号内指定父类的名称,例:class 子类名(父类名):

9.  在编写子类时,通常要调用父类的方法 __init__()。这将初始化在父类 __init__()方法中定义的所有属性,从而让子类包含这些属性。

10. super()是一个特殊函数,让子类能够调用父类的方法。例:super()__init__(形参1,形参2)(这里圆括号内填的是除 self 外的父类方法 __init__()中的所有形参)

程序:

class Car:
    """一次模拟汽车的简单尝试"""

    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.year}"
        return long_name.title()
    
    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it.")

    def updata_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 ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self,make,model,year):
        """初始化父类的属性"""
        super().__init__(make,model,year)
        self.battery_size = 75                                      #子类定义的一条新属性,并设置其初始值为75

    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.describe_battery()

======================== RESTART: E:/python3.9.2/car.py ========================
2019 Tesla 2019
This car has a 75-kWh battery.
>>> 

11. 重写父类的方法:可在子类中定义一个与要重写的父类方法同名的方法。这样,python 就不会考虑这个父类方法。

12. 将实例用作属性:

程序:

class Car:
    """一次模拟汽车的简单尝试"""

    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.year}"
        return long_name.title()
    
    def read_odometer(self):
        """打印一条指出汽车里程的消息"""
        print(f"This car has {self.odometer_reading} miles on it.")

    def updata_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.")
        
class ElectricCar(Car):
    """电动汽车的独特之处"""

    def __init__(self,make,model,year):
        """
        初始化父类的属性
        再初始化电动汽车独有的属性
        """
        super().__init__(make,model,year)
        self.battery = Battery()                                #将实例用作属性

my_tesla = ElectricCar('tesla','model S',2019)
print(my_tesla.get_descriptive_name())
my_tesla.battery.describe_battery()

======================== RESTART: E:/python3.9.2/car.py ========================
2019 Tesla 2019
This car has a 75-kWh battery.
>>> 

13. 为是文件尽可能整洁,python 允许将类存储在模块中,然后在主程序中导入所需的模块。

14.(1)导入类:from  模块名   import   类名

(2)从一个模块中导入多个类:from  模块名   import  类名1,类名2

(3)导入整个模块:import   模块名

(4)导入模块中的每个类:from  模块名  import*

注意:不推荐使用这种导入方式,原因:一、如果只看文件开头的 import 语句,就能清楚地知道程序使用了哪些类,将大有裨益。二、这种方式可能引发名称方面的疑惑,如果不小心导入了一个与程序文件中同名的类,将引发难以诊断的错误。

当需要从一个模块中导入许多类时,最好导入整个模块,并使用   模块名.类名    语法来访问类。

(5)导入类时为其指定别名:from  模块名  import   类名   as   别名

15.  一开始应该让代码结构尽可能简单。先尽可能在一个文件中完成所有的工作,确定一切都能正确运行后,再将类移到独立的模块中。如果你喜欢模块和文件的交互方式,可在项目开始时就尝试将类存储到模块中。先找出让你能够编写出可行代码的方式,再尝试改进代码。

16.  (1)Python 标准库是一组模块,我们安装的 python 都包含它。

(2)在模块 random 中,函数 randint()将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数。

(3)在模块 random 中,函数 choice()将一个列表或元组作为参数,并随机返回其中的一个元素。

(4)当创建与安全相关的应用程序时,请不要使用模块 random ,但该模块可以很好地用于创建众多有趣的项目。

17. (1) 类名应采用驼峰命名法,即将类中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写形式,并在单词之间加上下划线。

(2)对于每个类,都应紧跟在类定义后面包含一个文件字符串。这种文档字符串简要地描述类的功能,并遵循编写函数的文档字符串是采用的格式约定。每个模块也都应包含一个文档字符串,对其中的类可用于做什么进行描述。

(3)可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;在模块中,可使用两个空行来分隔类。

(4)需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 import 语句,在添加一个空行,然后编写导入你自己编写的模块的 import 语句。在包含多条 import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何处。

第十章    文件和异常

1.  函数  open('文件名') 打开文件。python 在当前执行文件所在的目录中查找指定的文件。

2. 关键词 with 在不再需要访问文件后将其关闭。

3.可以调用函数 open()和 close ()来打开和关闭文件,但这样做时,如果程序存在 bug 导致方法 close()未执行,文件将不会关闭,为妥善关闭文件可能导致数据丢失或受损。如果在程序中过早调用 close(),你会发现需要使用文件时它已关闭(无法访问),这会导致更多的错误。并非在任何情况下都能轻松确定关闭文件的恰当时机,但可以让 python 去确定:你只管打开文件,并在需要时使用它,python 自会在合适的时候自动将其关闭。

4.  函数 read()到达文件末尾时会返回一个空字符串,而将这个字符串显示出来时就是一个空行,可使用方法  rstrip()删除字符串末尾的空白。

程序:

with open('pi_digits.txt') as file_object:
    contents = file_object.read()
print(contents.rstrip())
==================== RESTART: E:\python3.9.2\file_reader.py ====================
3.1415926535
  8979323846
  2643383279
>>> 

5.(1) 相对文件路径:相对于当前运行的程序所在目录的位置。(文件夹 text_file 位于文件夹 python_work(程序所在文件夹)中)

(2)绝对文件路径:将文件在计算机中的准确位置告诉 python 。

(3)注意:显示文件路径时,Windows 系统使用反斜杠(\)而不是斜杠(/),但在代码中依然可以使用斜杠。如果在文件路径中直接使用反斜杠,将引发错误,因为反斜杠用于对字符串中的字符进行转义。(例:对于路径 "C:\path\to\file.txt",其中的 \t 将被解读为制表符。)如果一定要使用反斜杠,可对路径中的每个反斜杠都进行转义,如 "C:\\path\\to\\file.txt"。

6.  逐行读取文件

程序:

filename = 'pi_digits.txt'
with open(filename) as file_object:
    lines = file_object.readlines()
for line in lines:
        print(line.rstrip())

==================== RESTART: E:\python3.9.2\file_readers.py ===================
3.1415926535
  8979323846
  2643383279
>>> 

7.  方法 readline() 从文件中只读取第一行

方法 readlines () 从文件中读取每一行。

8.  读取文本文件时,python 将其中的所有文本都解读为字符串。如果读取的是数,并要将其作为数值使用,就必须用函数 int() 将其转换成整数或使用函数 float() 将其转换成浮点数。

程序:

filename = '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))

===================== RESTART: E:\python3.9.2\pi_string.py =====================
3.141592653589793238462643383279
32
>>> 

9.  写入文件的:

with  open(要打开的文件名称,'w') as  变量名:

    变量名.write("要写入的内容")

打开文件时,可指定读取模式('r')、写入模式('w')、附加模式('a')或读写模式('r+'),如果省略了模式实参,python 将以默认的只读模式打开文件。

10.  如果要写入的文件不存在,函数 open()将自动创建它。然而,以写入模式('w')打开文件时,如果指定的文件已经存在,python 将在返回文件对象前清空该文件的内容。

11. python 只能将字符串写入文本文件。要将数值数据存储到文本文件中,必须先使用函数 str() 将其转换为字符串格式。

12.  函数 write()不会再写入的文本末尾添加换行符,因此如果写入多行时需要自己指定换行符。

13.  如果要给文件添加内容,而不是覆盖原有的内容,可以以附加模式打开文件。以附加模式打开文件时,python 不会再返回文件对象前清空文件的内容,而是将写入文件的行添加到文件末尾。如果指定的文件不存在,python 将为你创建一个空文件。

程序:

filename = 'programming.txt'

with open(filename,'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")
with open(filename,'a') as file_object:
    file_object.write("I also love finding meaning in large datasets.\n")

 

14.  异常:python 创建的特殊对象,用来管理程序运行时出现的错误。

(1)处理 ZeroDivisionError 异常:当你用一个数除以 0 时,python 报错。

(2)使用 try-except 代码块:try 代码块让 python 尝试运行一些代码,except 代码块告诉它如果这些代码引发了指定的异常该怎么办。

(3)try-except-else 代码块:可以将依赖 try 代码块成功执行的代码都放在 else 代码块中。

程序:

print("Give me two numbers, and I'll divide them")
print("Enter 'q' to quit")

while True:
    first_name = input("\nFrist name: ")
    if first_name == 'q':
        break
    second_name = input("\nSecond name: ")
    if second_name == 'q':
        break
    try:
        answer = int(first_name)/int(second_name)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    else:
        print(f"answer: {answer}")

================ RESTART: E:\python3.9.2\division_calculator.py ================
Give me two numbers, and I'll divide them
Enter 'q' to quit

Frist name: 3

Second name: 0
You can't divide by 0!

Frist name: 3

Second name: 2
answer: 1.5

Frist name: 

(4)程序崩溃可不好,但让用户看到 traceback 也不是好主意。不懂技术的用户会被搞糊涂,怀有恶意的用户还会通过 traceback 获悉你不想他知道的信息。例如,他将知道你的程序文件的名称,还将看到部分不能正确运行的代码。有时候,训练有素的攻击者可根据这些信息判断出可对你的代码发起什么样的攻击。

(5)处理 FileNotFoundError 异常:查找的文件可能在其他地方,文件名可能不正确,或者这个文件根本就不存在。

(6)打开文件时注意:with  open(文件名或将文件赋给的变量名,'encoding=要读取的文件使用的编码') as   变量名1

(7)方法 split()以空格为分隔符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。结果是一个包含字符串中所有单词的列表,虽然有些单词可能包含标点。

程序:

def count_words(filename):
    try:    
        with open(filename,encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        print(f"Sorry, the file {filename} does not exist.")
    else:
        # 计算该文件大致包含多少个单词。
        words = contents.split()
        num_words = len(words)
        print(f"The file {filename} has about {num_words} words.")

filenames =['alice.txt','siddhartha','moby_dick.txt','little_women.txt']
for filename in filenames:
    count_words(filename)
======================= RESTART: E:\python3.9.2\alice.py =======================
The file alice.txt has about 29465 words.
Sorry, the file siddhartha does not exist.
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.
>>> 

(8)pass 语句:可用于让 python 在代码块中什么都不要做。pass 语句还充当了占位符,提醒你在某个地方什么都没有做,并且以后也许要在这里做些什么。
程序:

def count_words(filename):
    try:    
        with open(filename,encoding='utf-8') as f:
            contents = f.read()
    except FileNotFoundError:
        pass
    else:
        # 计算该文件大致包含多少个单词。
        words = contents.split()
        num_words = len(words)
        print(f"The file {filename} has about {num_words} words.")

filenames =['alice.txt','siddhartha','moby_dick.txt','little_women.txt']
for filename in filenames:
    count_words(filename)
======================= RESTART: E:\python3.9.2\alice.py =======================
The file alice.txt has about 29465 words.
The file moby_dick.txt has about 215830 words.
The file little_women.txt has about 189079 words.
>>> 

15.  (1)模块 json 让你能够将简单的 python 数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。,还可以使用 json 在 python 程序之间分享数据。

(2)JSON(JavaScript Object Notation)格式最初是为 JavaScript 开发的,但随后成了一种常见格式,被包括 Python 在内的众多语言采用。

(3)函数 json.dump(要存储的数据,要存储数据的文件对象(.json文件))  

注意:通常使用文件扩展名 .json 来指出文件存储的数据为 JSON 格式。

(4)函数 json.load(指向文件的变量名)

程序:

import json

# 如果以前存储了用户名就加载它。
# 否则,提示用户输入用户名并存储它。
filename = 'username.json'

try:
    with open(filename) as f:
        username = json.load(f)
except FileNotFoundError:
    username = input("What is your name?")
    with open(filename,'w') as f:
        json.dump(username,f)
        print(f"We'll remember you when you come back, {username}!")
else:
    print(f"Welcome back, {username}!")

==================== RESTART: E:/python3.9.2/remember_me.py ====================
What is your name?Jack
We'll remember you when you come back, Jack!
>>> 
==================== RESTART: E:/python3.9.2/remember_me.py ====================
Welcome back, Jack!
>>> 

16.  重构,将代码划分为一系列完成具体工作的函数。

第十一章  测试代码

1.  待测试函数:

def get_formatted_name(first,last):
    """生成整洁的姓名"""
    full_name = f"{first} {last}"
    return full_name.title()

=================== RESTART: E:\python3.9.2\name_function.py ===================
>>> 

测试函数:

from name_function import get_formatted_name

print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name:")
    if first == 'q':
        break
    last = input("please give me a last name:")
    if last == 'q':
        break
    formatted_name = get_formatted_name(first,last)
    print(f"\tNeatly formatted name: {formatted_name}.")

======================= RESTART: E:/python3.9.2/names.py =======================
Enter 'q' at any time to quit.

Please give me a first name:bob
please give me a last name:joplin
    Neatly formatted name: Bob Joplin.

Please give me a first name:q
>>> 

2. (1) Python 标准库中的模块 unittest 提供了代码测试工具。

(2)单元测试用于核实函数的某个方面没有问题

(3)测试用例是一组单元测试,他们一道核实函数在各种情况下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含所有针对这些情形的测试。

(4)全覆盖的测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。

3.  要为函数编写测试用例,可先导入模块 unittest 和要测试的函数,再创建一个继承 unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。

4.  断言方法:模块 unittest 类最有用的功能之一。断言方法核实得到的结果是否与期望的结果一致。

unittest 模块中的断言方法

方法 用途 assertEqual(a,b) 核实 a == b assertNotEqual(a,b) 核实 a != b assertTrue(x) 核实 x 为True assertFalse(x) 核实 x 为 False assertIn(item,list) 核实 item 在 list 中 assertNotIn(item,list) 核实 item 不在 list 中

5.  在测试中定义的方法必须以 test_  打头。如下列程序所示:

6.  测试函数 get_formatted_name()。

import unittest
from name_function import get_formatted_name

class NamesTestCase(unittest.TestCase):
    """测试 name_function.py。"""

    def test_first_last_name(self):                     #方法名必须以 test_  打头
        """能够正确地处理像 Janis Joplin 这样的姓名吗?"""
        formatted_name = get_formatted_name('janis','joplin')
        self.assertEqual(formatted_name,'Janis Joplin')

if __name__ == '__main__':
    unittest.main()

================= RESTART: E:/python3.9.2/test_name_function.py ================
.                                                                 #一个句点表示有一个单元测试通过了
----------------------------------------------------------------------
Ran 1 test in 0.004s                                  #表示消耗的时间为0.004s

OK                                                             #表明该测试用例中的所有单元测试都通过了
>>> 

注意到:if 代码块检查特殊变量  __name__,这个变量是在程序执行时设置的。如果这个文件作为主程序执行,变量  __name__  将被设置为 '__main__' 。在这里,调用 unittest.main()  来运行测试用例。

7.  方法 setUp() :包含在 unittest.TestCase 类中,让我们只需要创建对象一次,就能在每个测试方法中使用。如果在 TestCase 类中包含了方法 setUp()  ,Python 将先运行它,再运行各个以 test_  打头的方法。

程序:

创建一个待测类 AnonymousSurvey

class AnonymousSurvey:
    """收集匿名调查问卷的答案"""

    def __init__(self,question):
        """存储一个问题,并为存储答案做准备。"""
        self.question = question
        self.responses = []

    def show_question(self):
        """显示调查问卷。"""
        print(self.question)

    def store_response(self,new_response):
        """存储单份调查问卷。"""
        self.responses.append(new_response)

    def show_result(self):
        """显示收集到的所有答卷。"""
        print("Survey result")
        for response in self.responses:
            print(f"- {response}")

======================= RESTART: E:/python3.9.2/survey.py ======================
>>> 

测试类AnonymousSurvey

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
    """针对 AnonymousSurvey 类的测试。"""

    def setUp(self):
        """
        创建一个调查对象和一组答案,供使用的测试方法使用。
        """
        question = "What language did you first learn to speak?"
        self.my_survey = AnonymousSurvey(question)
        self.responses = ['English','Spanish','Mandarin']

    def test_store_single_response(self):
        """测试单个答案会被妥善地存储。"""
        self.my_survey.store_response(self.responses[0])
        self.assertIn(self.responses[0],self.my_survey.responses)

    def test_store_three_responses(self):
        """测试三个答案会被妥善地存储。"""
        for response in self.responses:
            self.my_survey.store_response(response)
        for response in self.responses:
            self.assertIn(response,self.my_survey.responses)

if __name__ == '__main__':
    unittest.main()

==================== RESTART: E:/python3.9.2/test_survey.py ====================
..
----------------------------------------------------------------------
Ran 2 tests in 0.009s

OK
>>> 

8.  运行测试用例时,每完成一个单元测试,python 都打印一个字符:测试通过是打印一个句点,测试引发错误时打印一个 E ,而测试导致断言失败时则打印一个 F 。

 

文章说明:本文共计3万多字,纯手打,希望能够帮到同我一样在进行 Python 学习的同学。

推荐一个别人写的关于这本书的笔记,感觉他写的比我写的好多了,清晰明了

链接:https://blog.csdn.net/weixin_45953673/article/details/105142089

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值