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

文章目录

  • 前言
  • 第二章 变量和简单数据类型
    • 一、变量的命名和使用
    • 二、字符串
    • 三、整数和浮点数
  • 第三章 列表简介
  • 第四章 操作列表
    • 一、列表
    • 二、元组
    • 三、设置代码格式
  • 第五章 if语句
  • 第六章 字典
    • 一、增删改查
    • 二、遍历字典
    • 三、嵌套
  • 第七章 用户输入和while循环
  • 第八章 函数
    • 一、函数
    • 二、返回值
    • 三、参数传递
    • 四、将函数存储在模块中
    • 五、函数编写指南
  • 第九章 类
    • 一、创建和使用类
    • 二、根据类创建实例
    • 三、继承
    • 四、导入类
    • 五、python标准库
    • 六、类编码风格
  • 第十章 文件和异常
    • 一、读取整个文件
    • 二、逐行读取
    • 三、创建一个包含文件各行内容的列表
    • 四、写入文件
    • 五、异常
    • 六、使用模块json存储数据
  • 第十一章 测试代码
    • 一、测试方法
    • 二、测试类
    • 三、方法setUp()
  • 总结


前言

如标题所示,就是在记笔记

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

一、变量的命名和使用

1.变量名只能包含字母、数字和下划线。变量名可以字母或下划线打头,但不能以数字打头。
2.变量名不能包含空格,但可使用下划线来分隔其中的单词。
3.不要将python关键字和函数名用作变量名,即不要使用python保留用于特数用途的单词
4.变量名应既简短又具有描述性
5.慎用小写字母 l 和大写字母O,因为它们可能被人错看成数字1和0
6.应使用小写的python变量名,在变量名中使用大写字母虽然不会导致错误,但避免使用大写字母是个不错的主意

二、字符串

1.在python中,用引号括起来的都是字符串,其中的引号可以是单引号,也可以是双引号。这种灵活性让你能够在字符串中包含 引号和撇号。
2.操作
(1)title() :以首字母大写的方式显示每个单词,即将每个单词的首字母都改为大写;upper()、lower()将字符串改为全部大写或全部小写
存储数据时,方法lower()很有用。很多时候无法依靠用户来提供正确的大小写,因此需要将字符串先转换为小写,再存储它们。以后需要显示这些信息时,再将其转换为最合适的大小写方式

name = "ada loveace"
print(name.title())
print(name.upper())
print(name.lower())

(2)在编程中,空白泛指任何非打印字符,如空格、制表符(\t)和换行符(\n)。
rstrip()、lstrip()、strip()分别删除末尾、开头和两端的空格

三、整数和浮点数

** 表示乘方运算
在字符串中使用整数时,需要显示地指出你希望python程序将这个整数用作字符串,可调用函数 str()
python使用 # 作为注释一行之后的内容

第三章 列表简介

列表由一系列特定顺序排列的元素组成,元素之间可以没有任何关系。鉴于列表通常包含多个元素,给列表指定一个表示复数的名称是个不错的主意。

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

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

访问列表元素

print(bicycles[0])
#trek

python为访问最后一个列表元素提供了一种特殊语法,通过将其索引值指定为-1,可以让python返回最后一个列表元素

print(bicycles[-1])
#specialized

修改列表元素

motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles[0] = 'ducati'
print(motorcycles)
#['ducati', 'yamaha', 'suzuki']

添加列表元素

motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles.append('ducati')
print(motorcycles)
#['honda', 'yamaha', 'suzuki','ducati']

插入列表元素

motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles.insert(0,'ducati')
print(motorcycles)
#['ducati', 'honda', 'yamaha', 'suzuki']

使用del语句删除元素

motorcycles = ['honda', 'yamaha', 'suzuki']
del motorcycles[0]
print(motorcycles)
#['yamaha', 'suzuki']

使用pop()删除元素

motorcycles = ['honda', 'yamaha', 'suzuki']
popped_motorcycle = motorcycles.pop()
print(motorcycles)
#['honda', 'yamaha']
print(popped_motorcycle)
#suzuki

使用pop()弹出列表中任何位置处的元素

motorcycles = ['honda', 'yamaha', 'suzuki']
first_owned = motorcycles.pop(0)

根据值删除元素.方法remove()只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值

motorcycles = ['honda', 'yamaha', 'suzuki','ducati']
motorcycles.remove('ducati')
print(motorcycles)

使用方法sort()对列表进行永久性排序,默认按照字母顺序排序,sort(reverse=True)可以进行逆序排序

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

使用函数sorted()对列表进行临时排序,如 sorted(cars),可以传递参数reverse=True 进行逆序排序
可以使用reverse()反转列表元素的排列顺序

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

确定列表长度

cars = ['bmw', 'audi', 'toyota' ,'subaru']
len(cars)
#4

第四章 操作列表

一、列表

遍历列表

magicians = ['alice', 'david' ,'carolina']
for magician in magicians:print(magician)

函数range()让python从你指定的第一个值开始数,并在到达你指定的第二个值后停止,因此输出不包含第二个值

for value in range(1,5):print(value)

创建数值列表,列表非常适合于存储数字集合,可使用list()函数将range()的结果直接转换为列表,range()函数还可以指定步长。可以使用max()、min()、sum()对数字列表进行简单的统计计算

numbers = list(range(1,6))
print(numbers)

列表解析

squares = [value ** 2 for value in range(1,11)]
print(squares)

切片:要创建切片,可指定要使用的第一个元素和最后一个元素的索引。和range()函数一样,python在到达你指定的第二个索引前面的元素后停止。如果没有指定第一个索引,从列表开头开始;省略终止索引,切片终止于列表末尾;需要最后三个元素,可使用切片 player[-3:] ;同时省略起始索引和终止索引( [:] ),python会创建一个始于第一个元素,终止于最后一个元素的切片,即复制整个列表。直接赋值的话得到的只是引用。

player = ['charles','martina','michael','florence','eli']
print(player[0:3])

二、元组

列表是可以修改的,元组是不可修改的。python将不能修改的值称为不可变的,而不可变的列表被称为元组。
元组看起来犹如列表,但使用圆括号而不是方括号来标识。定义元组后,就可以使用索引来访问其元素,就像访问列表元素一样。
虽然不能修改元组的元素,但可以给存储元组的变量赋值,或者可以说是修改元组的引用。
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不可变,可使用元组。

三、设置代码格式

1.PEP8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。在程序中混合使用制表符和空格可能导致极难解决的问题。如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
2.每行不超过80个字符,注释的行长不超过72字符。大多数编辑器中,都可设置一个视觉标志——通常是一条竖线,让你知道不能越过的界限在什么地方。
3.将程序的不同部分分开,可使用空行。

第五章 if语句

每条if语句的核心都是一个值为True或False的表达式,这种表达式称为条件测试 或 布尔表达式
在python中检查是否相等时区分大小写,例如,两个大小写不同的值会被视为不相等。
如果大小写无关紧要,而只想检查变量的值,可将变量的值转换为小写,再进行比较。
函数 lower() 不会修改存储在变量中的值,因此进行这样的比较时不会影响原来的变量。
检查多个条件时可用关键字 and 和 or
检查特定值是否包含在列表中,可使用关键字 in
检查特定值是否不包含在列表中,可使用关键字 not in

简单的 if 语句

if conditional_testdo something

if-else 结构
if-elif-else 结构
使用任意数量的 elif 代码块
可以省略 else 代码块,经过这样的修改后,每个代码块都仅在通过相应的测试时才会执行。 else 是一条保罗万象的语句,只要不满足任何 if 或 elif 中的条件测试,其中的代码就会执行,这可能引入无效甚至恶意的数据。
如果你只想执行一个代码块,就是用if-elif-else结构,如果要运行多个代码块,就使用一系列独立的 if 语句。
** 在if语句中将列表名用在条件表达式中时,python将在列表至少包含一个元素时返回True,并在列表为空时返回False**
** 在诸如 == >= <= 等比较运算符两边各添加一个空格,这样的空格不会影响python对代码的解读,而只是让代码阅读起来更容易**

第六章 字典

一、增删改查

一个简单的字典

alien_0 = {'color':'green','points':5}print(alien_0['color'])
print(alien_0['points'])

在python中,字典是一系列键-值对,字典用放在花括号 {} 中的一系列键-值对表示。指定键时,python将返回与之相关联的值。键和值之间用冒号分隔,而键-值对之间用逗号分隔。在字典中,你想存储多少个键-值对都可以。
获取与键相关联的值,可依次指定字典名和放在方括号内的键
添加键-值对:字典是一种动态结构,可随时在其中添加键-值对,要添加键-值对,可依次指定字典名、用方括号括起来的键和相关联的值。
键-值对的排列顺序与添加顺序不同,python不关心键-值对的添加顺序,而只关心键和值之间的关联关系
创建一个空字典,使用字典来存储用户提供的数据或在编写能自动生成大量键-值对的代码时,通常都需要先定义一个空字典

alien_0 = {}

修改字典中的值:要修改字典中的值,可依次指定字典名、用方括号括起来的键以及与该键相关联的新值。
删除键-值对:对于字典中不再需要的信息,可使用 del 语句将相应的键-值对彻底删除。使用del语句时,必须指定字典名和要删除的键。

del alien_0['points']

确定需要使用多行来定义字典时,在输入左花括号后按回车键,再在下一行缩进四个空格,指定第一个键-值对,并在它后面加上一个逗号。此后你再次按回车键时,文本编辑器将自动缩进后续键-值对,且缩进量与第一个键-值对相同。
定义好字典后,在最后一个键-值对的下一行添加一个右花括号,并缩进四个空格,使其与字典中的键对齐。另外一种不错的做法是在最后一个键-值对后面也加上逗号,为以后在下一行添加键-值对做好准备。

favorite_languages = {'jen':'python','sarah':'c','edward':'ruby','phil':'python',}
print("Sarah's favorite language is " +favorite_languages['sarah'].title() +".")

二、遍历字典

遍历所有的键-值对,for语句的第二部分包含字典名和方法 items() ,它返回一个键-值对列表,for循环依次将每个键-值对存储到指定的两个变量中。即使遍历字典时,键-值对的返回顺序也与存储顺序不同。python不关心键-值对的存储顺序,而只跟踪键和值之间的关联关系

user_0 = {'username':'efermi','first':'enrico','last':'fermi',}
for key, value in user_0.items():print("\nKey: "+key)print("Value: "+value)

遍历所有的键。遍历字典时,会默认遍历所有的键。因此将下面的for name in favorite_languages.keys() 替换为 for name in favorite_languages 输出将不变。如果显示地使用方法 keys() 可让代码更容易理解。在这种循环中,可使用当前的键来访问与之相关联的值。 方法keys()并非只能用于遍历;实际上,它返回一个列表,其中包含字典中所有的键。

favorite_languages = {'jen':'python','sarah':'c','edward':'ruby','phil':'python',}
for name in favorite_languages.keys():print(name)

要以特定的顺序返回元素,一种办法是在for循环中对返回的键进行排序。可使用函数sorted()来获得按特定顺序排列的键列表的副本

favorite_languages = {'jen':'python','sarah':'c','edward':'ruby','phil':'python',}
for name in sorted(favorite_languages.keys()):print(name.title() + ', thank you for taking poll.')

遍历字典中所有的值,可使用方法values(),它返回一个值列表,而不包含任何键。这种做法提取字典中所有的值,而没有考虑是否重复。为剔除重复项,可使用集合(set)。集合类似于列表,但每个元素都必须是独一无二的。

favorite_languages = {'jen':'python','sarah':'c','edward':'ruby','phil':'python',}
print('The following languages hava been mentioned')
for language in set(favorite_languages.values()):print(language.title())

三、嵌套

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

alien_0 = {'color': 'green', 'points': 5}
alien_1 = {'color': 'yellow', 'points': 10}
alien_2 = {'color': 'red', 'points': 15}aliens = [alien_0, alien_1 ,alien_2]for alien in aliens:print(alien)

在字典中存储列表

#存储所点pizza信息
pizza = {'crust': 'thick','toppings': ['mushrooms',  'extra cheese']}
#概述所点的pizza
print("You ordered a " + pizza['crust'] + "-crust pizza" +"with the following toppings:")for topping in pizza['toppings']:print("\t" + topping)

在字典中存储字典

users = {'aeinstein':{'first':'albert','last':'einstein','location':'princeton',},'mcurie':{'first': 'marie','last': 'curie','location':'paris',}}
for username, user_info in users.items():print("\nUsername: " + username)full_name = user_info['first'] + " " + user_info['last']location = user_info['location']print("\tFull name: " + full_name.title())print("\tLocation: " + location.title())

第七章 用户输入和while循环

函数input()让程序暂停运行,等待用户输入一些文本。获得用户输入后,python将其存储在一个变量中,以方便你使用
使用函数input()时,python将用户输入解读为字符串,使用函数int()可将数字的字符串表示转换为数值表示
在python2.7中应使用函数raw_input()来提示用户输入,这个函数与在python3中的input()一样,也将输入解读为字符串
while、break、continue 比较简单,不再赘述

第八章 函数

一、函数

三个引号包起来的文本被称为文档字符串的注释,描述了函数是做什么的

def greet_user():"""显示简单的问候语"""print("Hello!")greet_user()

函数的参数传递
(1)位置实参,按照形参的声明的顺序把实参赋给形参
(2)关键字实参是传递给函数的 名称-值 对,直接在实参中将名称和值关联起来了,因此向函数传递实参时不会混淆。关键字实参让你无需考虑函数调用中的实参顺序。 使用关键字实参时,务必准确地指出函数定义中的形参名
(3)默认值。编写函数时,可给每个形参指定默认值。在调用函数中给形参提供了实参时,python将使用指定的实参值;否则,将使用形参的默认值。默认值放在形参的最后位置

二、返回值

(1)让实参变成可选的python将非空字符串解读为True

def get_formatted_name(first_name,last_name,middle_name=''):"""返回整洁的姓名"""if middle_name:full_name = first_name + '' + middle_name + '' + last_nameelse:full_name = first_name + '' + last_namereturn full_name.title()

(2)返回字典或列表(比较简单,不再赘述)

三、参数传递

(1)在函数中修改列表
将列表传递给函数后,函数就可对其进行修改。在函数中对这个列表的所做的任何修改都是永久性的。这个可以这样理解,给函数传递的参数都是引用,所以函数对对形参所作的操作其实就是对实参进行操作

def print_models(unprinted_designs, completed_models):"""模拟打印每个设计,直到没有未打印的设计为止打印每个设计后,都将其移到列表completed_models中"""while unprinted_designs:current_design = unprinted_designs.pop()# 模拟根据设计制作3D打印模型的过程print("Printing model: " + current_design)completed_models.append(current_design)def show_completed_models(completed_models):"""显示打印好的所有模型"""print("\nThe following models have been printed")for completed_model in completed_models:print(completed_model)
# 首先创建一个列表
unprinted_designs = ['iphone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs,completed_models)
show_completed_models(completed_models)

(2)禁止函数修改列表,可向函数传递实参的副本,即传递 list_name[:]
虽然向函数传递列表的副本可保留原始列表的内容,但除非有充分的理由需要传递副本,否则还是应该将原始列表传递给函数,因为让函数使用现成的列表可避免花时间和内存创建副本,从而提高效率
(3)传递任意数量的实参

def make_pizza(*toppings):print(toppings)

形参名*toppings中的星号让python创建一个名为toppings的空元组,并将收到的所有值都封装到这个元组中。
(4)结合使用位置和任意数量实参

def make_pizza(size,*toppings):pass

(5)使用任意数量的关键字实参

def build_profile(first,last,**user_info):"""创建一个字典,其中包含我们知道的有关用户的一切"""profile = {}profile['first_name'] = firstprofile['last_name'] = lastfor key, value in user_info.items():profile[key] = valuereturn profileuser_profile = build_profile('albert','einstein',location='princeton',field='physics')
print(user_profile)
#{'first_name': 'albert', 'last_name': 'einstein', 'location': 'princeton', 'field': 'physics'}

四、将函数存储在模块中

函数的优点之一是,使用它们可将代码块与主程序分离。更可以进一步,将函数存储在被称为模块的独立文件中,再将模块导入到主程序中。模块是拓展名为.py的文件。import语句允许在当前运行的程序文件中使用模块的代码
(1)导入整个模块,要调用被导入的模块中的函数,可指定导入的模块的名称pizza和函数名make_pizza(),并用句点分隔它们
pizza.py

def make_pizza(size, **toppings):"""概述要制作的比萨"""print("\nMaking a " + str(size) +"-inch pizza with the following toppings")for topping in toppings:print("- " + topping)

making_pizzas.py

import pizzapizza.make_pizza(16, 'pepperoni')

(2)导入特定模块,若使用这种语法,调用函数时就无需使用句点,直接指定函数的名称即可
from module_name import function_name
from module_name import function_0,function_1,function_2
(3)使用as给函数指定别名
from module_name import function_name as fn

from pizza import make_pizza as mp
mp(16,'pepperoni')

(4)使用as给模块指定别名
import module_name as mn
(5)导入模块中所有函数,import中的星号让python将模块pizza中的每个函数都复制到这个程序文件中,可通过函数名称直接调用。
然而使用并非自己编写的大型模块最好不要采用这种导入方法:如果模块中有函数的名称与你项目中使用的名称相同,可能导致意想不到的结果:python可能遇到多个名称相同的函数或变量,进而覆盖函数,而不是分别导入所有的函数
from module_name import *

五、函数编写指南

(1)编写函数时,应给函数指定描述性名称,且只在其中使用小写字母和下划线。
(2)每个函数都应包含简要地阐述其功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式
(3)给形参指定默认值时,等号两边不要有空格,对于函数调用中的关键字实参,也应遵循这种约定
(4)PEP8建议代码行的长度不要超过79字符,如果形参很多,导致函数定义的长度超过了79字符,可在函数定义中输入左括号后按回车键,并在下一行按两次Tab键,从而将形参列表和只缩进一层的函数体区分开来
(5)如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开,这样更容易知道前一个函数在什么地方结束,下一个函数从什么地方开始
(6)所有import语句应放在文件开头,除了在文件开头使用了注释来描述整个程序

第九章 类

一、创建和使用类

__init()__是一个特殊的方法,每当你根据Dog类创建新实例时,python都会自动运行它。这个方法的名称中,开头和结尾各有两个下划线,这是一种约定,旨在避免python默认方法与普通方法发生名称冲突。并未显式的包含return语句,python会自动返回实例对象
__init()__定义包含三个形参:self、name、age。在这个方法中,self必不可少且必须位于其他形参前面。因为python调用这个__init()__方法来创建Dog实例时,将自动传入实参self,它是一个指定实例本身的引用,让实例能够访问类中的属性和方法。每当我们根据Dog类创建实例时,都只需给最后两个形参提供值
类名首字母大写

class Dog():"""一次模拟小狗的简单尝试"""def __init__(self,name,age):"""初始化属性name和age"""self.name = nameself.age = agedef sit(self):"""模拟小狗被命令时蹲下"""print(self.name.title() + " is now sitting")def roll_over(self):"""模拟小狗被命令时打滚"""print(self.name.title() + " rolled over!")

二、根据类创建实例

my_dog = Dog('willie', 6)print("My Dog's name is " + my_dog.name.title() + ".")
print("My dog is " + str(my_dog.age) + " years old")

可以给属性指定默认值
修改属性的值:直接修改属性的值、通过方法修改属性的值、通过方法对属性的值进行递增。(比较简单,不再赘述)

三、继承

一个类继承另一个类时,它将自动获得另一个类的所有属性和方法
创建子类的实例时,python首先需要完成的任务是给父类的所有属性赋值
创建子类时,父类必须包含在当前文件中,且位于子类前面

class Car():"""一次模拟汽车的简单尝试"""def __init__(self,make,model,year):self.make = makeself.model = modelself.year = yearself.odometer_reading = 0def get_descriptive_name(self):long_name = str(self.year) + " " + self.make + " " + self.modelreturn long_name.title()def read_odometer(self):print("This car has " + str(self.odometer_reading) + " miles on it")def update_odometer(self, mileage):if mileage >= self.odometer_reading:self.odometer_reading = mileageelse:print("You can't roll back an odometer!")def increment_odometer(self,miles):self.odometer_reading += milesclass ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self,make,model,year):"""初始化父类的属性"""super().__init__(make,model,year)my_tesla = ElectricCar('tesla', 'model_s', 2016)
print(my_tesla.get_descriptive_name())

重写父类的方法,子类中的方法与要重写的父类方法同名,这样,python将不会考虑这个父类方法,而只关注在子类中定义的相应方法
。使用继承时,可让子类保留从父类那里继承而来的精华,并剔除不需要的糟粕(比较简单,不在赘述)
使用代码模拟实物时,可能会发现自己给类添加的细节越来越多,属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类拆分成多个协同工作的小类

四、导入类

随着不断给类添加功能,文件可能变得很长,即使妥善使用了继承亦如此。python允许你将类存储在模块中,然后在主程序中导入所需的模块
1.导入单个类

car.py

class Car():"""一个用于表示汽车的类"""def __init__(self,make,model,year):self.make = makeself.model = modelself.year = yearself.odometer_reading = 0def get_descriptive_name(self):long_name = str(self.year) + " " + self.make + " " + self.modelreturn long_name.title()def read_odometer(self):print("This car has " + str(self.odometer_reading) + " miles on it")def update_odometer(self, mileage):if mileage >= self.odometer_reading:self.odometer_reading = mileageelse:print("You can't roll back an odometer!")def increment_odometer(self,miles):self.odometer_reading += miles

my_car.py

from car import Car
my_new_car = Car('audi','a4',2016)

每个模块应该包含一个模块级文档字符串,对该模块的内容做简要的描述
使用 import 打开模块car,并导入其中的Car类,就可以使用Car类了
2.从一个模块中导入多个类

from car import Car,ElectricCar

3.导入整个模块,使用句点表示法访问需要的类

import carmy_beetle = car.Car('volkswagen','beetle',2016)

4.导入模块中的所有类

from module_name import *

不推荐使用这种导入方式
(1)没有明确指出使用了模块中的哪些类(2)如果导入了一个与程序文件中其他东西同名的类,将引发难以诊断的错误
5.在一个模块中导入另一个模块
有时候需要将类分散到多个模块中,以免模块太大,或在同一个模块中存储不相关的类。将类存储在多个模块时,可能发现一个模块中的类依赖另一个模块中的类,这是可在前一个模块中导入必要的类

五、python标准库

要创建字典并记录其中的键-值对的添加顺序,可使用模块collections中的OrderedDict类。OrderedDict 实例的行为几乎与字典相同,区别只在于记录了键-值对的添加顺序

from _collections import OrderedDict
favorite_languages = OrderedDict()favorite_languages['jen'] = 'python'
favorite_languages['sarah'] = 'c'
favorite_languages['edward'] = 'ruby'
favorite_languages['phil'] = 'python'for name,language in favorite_languages.items():print(name.title() + "'s favorite language is " + language.title() + ".")

六、类编码风格

1.类名应该采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线
2.对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应该包含一个文档字符串,对其中的类可用于做什么进行描述
3.可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,对可使用两个空行来分隔类。
4.需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的import语句,再添加一个空行,然后编写导入你自己编写的模块的import语句。

第十章 文件和异常

一、读取整个文件

pi_digits.txt

3.141592653589793238462643383279

file_reader.py

with open('pi_digits.txt') as file_object:contents = file_object.read()print(contents)

python在file_reader.py所在的目录中查找pi_digits.txt , 函数open()返回一个表示文件的对象,python将这个对象存储在我们将在后面使用的变量中
关键字with在不再需要访问文件后将其关闭。在这个程序中我们调用了open(),但没有调用close();你也可以调用open()和close()来打开和关闭文件,但这样做时,如果程序存在bug,导致close()语句未执行,文件将不会关闭。这看似微不足道,但为妥善地关闭文件可能会导致数据丢失或受损。如果在程序中过早地调用close(),会发现需要使用文件时它已关闭(无法访问),这会导致更多的错误。并非在任何时候都能轻松确定关闭文件的恰当时机,但通过使用前面所示的结构,可让python去确定;你只管打开文件,并在需要时使用它,python自会在合适的时候自动将其关闭。
相比于原始文件,该输出唯一不同的地方是末尾多了一个空行。为何会多出这个空行呢?因为read()到达文件末尾时返回一个空字符串,而将这个空字符串显示出来时就是一个空行。要删除多出来的空行,可在print语句中使用rstrip()
文件路径问题:绝对、相对、当前目录(比较简单,不再赘述)

二、逐行读取

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

print语句会输出一个换行符,文件中每行的末尾也会有一个换行符,使用rstrip()去掉每行末尾的换行符

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

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

四、写入文件

filename = 'programming.txt'with open(filename,'w') as file_object:file_object.write("I love programming")

打开文件时,可指定读取模式(‘r’)、写入模式(‘w’)、附加模式(‘a’)或让你能够读取和写入文件的模式(’ r+ ')。如果省略了模式实参,python将以默认的只读模式打开文件。 如果你要写入的文件不存在,函数open()将自动创建它。然而,以写入(‘w’)模式打开文件时要小心,因为如果指定的文件已经存在,python将在返回文件对象前清空该文件。
python只能将字符串写入文本文件中,要将数值数据存储到文本文件中,必须先使用函数 str() 将其转换为字符串格式

五、异常

1.ZeroDivisionError异常

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':breaksecond_number = input("Second number: ")try:answer = int(first_number) / int(second_number)except ZeroDivisionError:print("You can't devide by 0!")else:print(answer)

try-except-else 代码块的工作原理大致如下:python尝试执行try代码块中的代码;只有可能引发异常的代码才需要放在try语句中。当try代码块成功执行时会执行else代码块,否则执行except代码块
2.FileNotFoundError异常

filename = 'alice.txt'try:with open(filename) as f_obj:contents = f_obj.read()
except FileNotFoundError:msg = "Sorry, the file " + filename + " does not exist."print(msg)

在什么情况下该向用户报告错误?在什么情况下应该在失败时一声不吭呢?如果用户知道要分析哪些文件,他们可能希望在有文件没有分析时出现一条消息,将其中的原因告诉他们。如果用户只想看到结果,而并不知道要分析哪些文件,可能就无需在有些文件不存在时告知他们。
编写得很好且经过详尽测试的代码不容易出现内部错误,如语法或逻辑错误,但只有程序依赖于外部因素,如用户输入、存在指定的文件、有网络链接,就有可能出现异常。凭借经验可判断该在程序的什么地方包含异常处理块,以及出现错误时该向用户提供多少相关的信息

六、使用模块json存储数据

JSON(JavaScript Object Notation)格式最初是为JavaScript开发的,但随后成了一种常见格式,被包含python在内的众多语言采用
使用json.dump()存储数字列表

import jsonnumbers = [2, 3, 5, 7, 11, 13]filename = 'numbers.json'
with open(filename,'w') as f_obj:json.dump(numbers,f_obj)
#[2, 3, 5, 7, 11, 13]

使用json.load()加载存储在numbers.json中的信息

import jsonfilename = 'numbers.json'
with open(filename) as f_obj:numbers = json.load(f_obj)
print(numbers)

问候用户

import jsondef get_stored_username():"""如果存储了用户名,就获取它"""filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:return Noneelse:return usernamedef get_new_username():"""提示用户输入用户名"""username = input("What is your name? ")filename = 'username.json'with open(filename,'w') as f_obj:json.dump(username,f_obj)return usernamedef greet_user():"""问候用户,并指出其名字"""username = get_stored_username()if username:print("Welcome back, " + username + "!")else:username = get_new_username()print("We'll remember you when you come back, " + username + "!")greet_user()

第十一章 测试代码

python标准库中的模块unittest提供了代码测试工具。单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。

一、测试方法

name_function.py

def get_formatted_name(first, last):"""Generate a neatly formatted full name."""full_name = first + ' ' + lastreturn full_name.title()

test_name_function.py

import unittest
from name_function import get_formatted_nameclass NamesTestCase(unittest.TestCase):"""测试name_function.py"""def test_first_last_name(self):"""能够正确地处理像Janis Joplin 这样的姓名吗? """formatted_name = get_formatted_name('janis','joplin')self.assertEqual(formatted_name,'Janis Joplin')def test_first_last_middle_name(self):"""能够正确地处理像 Wolfgang Amadeus Mozart 这样的姓名吗"""formatted_name = get_formatted_name('Wolfgang', 'Amadeus', 'Mozart')self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')unittest.main()

我们运行test_name_function.py时,所有以 test_ 打头的方法都将自动运行。输出第一行的句点表明有一个测试通过了,E表示测试没有通过,下面是一些错误信息。最后是OK表明该测试用例中的所有单元测试都通过了,为FAILED表示有测试用例没有通过

二、测试类

survey.py

class AnonymousSurvey():"""收集匿名调查问卷的答案"""def __init__(self, question):"""存储一个问题,并为存储答案做准备"""self.question = questionself.responses = []def show_question(self):"""显示调查问卷"""print(self.question)def store_response(self, new_response):"""存储单份调查答卷"""self.responses.append(new_response)def show_results(self):"""显示收集到的所有答卷"""print("Survey results:")for response in self.responses:print('- ' + response)

test_survey.py

import unittest
from survey import AnonymousSurveyclass TestAnonmyousSurvey(unittest.TestCase):"""针对AnonymousSurvey类的测试"""def teststore_single_response(self):"""测试单个答案会被妥善地存储"""question = "What language did you first learn to speak?"my_survey = AnonymousSurvey(question)my_survey.store_response('English')self.assertIn('English', my_survey.responses)def test_store_three_responses(self):"""测试三个答案会被妥善地存储"""question = "What language did you first learn to speak?"my_survey = AnonymousSurvey(question)responses = ['English', 'Spanish', 'Mandarin']for response in responses:my_survey.store_response(response)for response in responses:self.assertIn(response,my_survey.responses)unittest.main

刚开始我写的 main() ,提示 “No tests were found ”,后来我写成了 main 就可以了,原因不知

三、方法setUp()

import unittest
from survey import AnonymousSurveyclass TestAnonmyousSurvey(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 teststore_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)unittest.main

方法setUp()做了两件事情:创建一个调查对象;创建一个答案列表。存储这两样东西的变量名包含前缀self(即存储在属性中),因此可以在这个类的任何地方使用。测试方法就不用创建调查对象和答案了
运行测试用例时,每完成一个单元测试,python都打印一个字符,测试通过时打印一个句点,测试引发错误时打印一个E,测试导致断言失败打印一个F。


总结

这篇博客是我照着python编程从入门到实践一书写的,是我边看书边记的笔记,防止自己看完之后像没看一样,我写了自己觉得重要的笔记,后面的项目部分就不适合记笔记了,还是要多实践。