第九章 类
面向对象编程是最有效的软件编写方法之一。基于类创造对象时,每个对象都自动具备这种通用行为,然后根据需要赋予每个对象独特的个性。
根据类创造对象被称为实例化。
9.1 创建和使用类
9.1.1 创建dog类
根据dog类创建的每个实例都将存储名字和年龄。
class Dog():
def __init__(self,name,age):
self.name=name
self.age=age
def sit(self)
print(self.name.title()+'is now sitting!')
def roll_over(self)
print(self.name.title()+'roller over!')
在第一行,定义了一个Dog的类
根据python约定,首字母大写的名称是类。在这个类定义的括号是空的,因为要从空白开始创建这个类。
在接下来的行数中,编写了一个文档字符串,对这一类功能进行描述。
1.方法_init_()
类中的函数称为方法;区别在于调用方法的方式。在第二行方法_init_()是一个特殊的方法,每当根据Dog类创建新实例时,python会自动运行它。这种方法的名称中,开头、末尾都有两个下划线,这是一种约定,为了避免python默认方法和普通方法名称冲突。
将方法__init__()定义成包含三个形参,在这个方法的定义中,形参self必不可少,并且必须其他形参前面。
为什么必须在方法中包含形参self?因为python调用这个__inint__()方法创建Dog实例时,将自动传入实参self,每个与类相关联的方法调用都自动传递实参self,他是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
创建Dog实例,python将调用Dog类的方法_init_()。通过实参向Dog()传递名字和年龄;self会自动传递,因此不需要传递给他值。每次根据Dog创建实例时,都只需要给最后面的两个形参(name和age)提供值。
第三行处定义了两个变量前缀都有self。以self为前缀的变量可供类中的所有方法使用,还可通过类的任何实例来访问这些变量。
self.name=name获取存储在形参name中的值,并将其存储到变量name中,然后该变量被关联到当前创建的实例。
可通过实例访问的变量称为属性
2.在python2.7中创建类
class ClassName(object)
多了在括号包含单词object
比如定义上面的例子
class Dog(object)
9.1.2 根据类创建实例
class Dog():
def __init__(self,name,age):
self.name=name
self.age=age
def sit(self):
print(self.name.title()+'is now sitting!')
def roll_over(self):
print(self.name.title()+'roller over!')
mydog=Dog('beibei',6)
print("my dog's is "+mydog.name.title()+".")
print("my dog's is "+str(mydog.age)+"years old.")
刚开始咋试都报错
后来通过百度查找,知道init左右两边是两个_,不是一个__
这里使用的是Dog类,python的实参'beibei'和6调用Dog类中的方法__init__(),方法__init__()创建一个特定小狗的示例,并使用我们提供的值来设置属性name,age。
方法__init__()没有return语句,但python会自动返回一个表示这小狗的实例。并将其存储在mydog这一变量中。
mydog是根据类创造的实例。
1.访问属性
访问实例属性,使用句点表示法。先找实例,再找实例相关的属性
2.调用方法
自己理解:关于mydog的第一行先调用方法,并且对def init()方法的两个属性mydog.name,mydog.age的陈述,遇到代码mydog.sit()时,python在类Dog中查询方法sit并执行其代码。
3.创建多个实例
class Dog():
def __init__(self,name,age):
self.name=name
self.age=age
def sit(self):
print(self.name.title()+'is now sitting!')
def roll_over(self):
print(self.name.title()+'roller over!')
mydog=Dog('beibei',6)
yourdog=Dog('dada',4)
print("my dog's is "+mydog.name.title()+".")
print("my dog's is "+str(mydog.age)+"years old.")
mydog.sit()
print("my dog's is "+yourdog.name.title()+".")
print("my dog's is "+str(yourdog.age)+"years old.")
yourdog.sit()
创建两条狗,每条狗都有自己的实例,有自己的一组属性,恩能执行相同的操作。
如果第二条狗指定相同的名字,也会根据Dog类创建另一个实例
9-1 餐馆 : 创建一个名为Restaurant 的类, 其方法__init__() 设置两个属性: restaurant_name 和cuisine_type 。 创建一个名
为describe_restaurant() 的方法和一个名为open_restaurant() 的方法, 其中前者打印前述两项信息, 而后者打印一条消息, 指出餐馆正在营业。根据这个类创建一个名为restaurant 的实例, 分别打印其两个属性, 再调用前述两个方法。
class Restaurant():
def __init__(self,restaurant_name,cuisine_type):
self.restaurant_name = restaurant_name
self.cuisine_type = cuisine_type
def describe_restaurant(self):
print(self.restaurant_name)
print(self.cuisine_type)
def open_restaurant(self):
print('Restaurant is open')
restaurant1=Restaurant('ali','china')
print('the restaurant1 is '+restaurant1.restaurant_name.title()+',main '+restaurant1.cuisine_type+'!')
restaurant1.describe_restaurant()
restaurant1.open_restaurant()
对类和属性的理解,自己老忘记restaruant1作为前缀。。。
9-3 用户 : 创建一个名为User 的类, 其中包含属性first_name 和last_name , 还有用户简介通常会存储的其他几个属性。 在类User 中定义一个名为describe_user() 的方法, 它打印用户信息摘要; 再定义一个名为greet_user() 的方法, 它向用户发出个性化的问候。创建多个表示不同用户的实例, 并对每个实例都调用上述两个方法
class User():
def __init__(self, first_name,last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print('用户名称为:' + self.first_name+' '+self.last_name)
def greet_user(self):
print('你好! ' + self.first_name+' '+self.last_name)
user_a = User('chen','youixu')
user_b = User('ma','siwei')
user_c = User('liu','bangbang')
user_a.describe_user()
user_a.greet_user()
user_b.describe_user()
user_b.greet_user()
user_c.describe_user()
user_c.greet_user()
9.2 使用类和实例
修改实例的属性,可以直接修改实例属性,也可以编写方法以特定的方式进行修改。
9.2.1 Car类
class Car():
def __init__(self,make,model,year):
self.make=make
self.model=model
self.year=year
def juti(self):
che=str(self.year)+' '+self.make+' '+self.model
return che.title()
mycar=Car('aodi','a99',2020)
print(mycar.juti())
2020 Aodi A99
自己没有注意关于空格的问题,忘了,空格前后要是都有调用的类的属性,必须左右都得加+,在调用其他情况下也适用,不然会显示 SyntaxError: invalid syntax
在首个def函数中,定义了方法,有三个形参。方法接受这些形参的值,并将他们存储在根据这个类创建的实例的变量中。
9.2.2 给属性指定默认属性
类中的每个属性必须有初始值,哪怕这个值是0或空字符串。可以设置默认的,再方法__inint__()内指定这种初始值是可行的;如果对某个属性这样做了,就无需包含为它提供初始的形参。
刚才百度了一下--snip--是啥用法。。
就是省略代码了,把前面的复制黏贴到这里的snif就行了。
当python调用方法__init__()来创建新实例时,将像前面实例那样以属性的方式存储信息,接下来创建一个名为oder的属性,并将其初始值设置为0
9.2.3 修改属性的值
三种方法:直接通过实例进行修改;通过方法进行设置;通过方法进行递增(增加特定的值)。
1.直接修改属性的值
通过实例直接访问它。
class Car():
def __init__(self,make,model,year):
self.make=make
self.model=model
self.year=year
self.oder=0
def juti(self):
che=str(self.year)+' '+self.make+' '+ self.model
return che.title()
def cheche(self):
print("this car has "+str(self.oder)+" miles on it !")
mycar=Car('aodi','a98',2020)
print(mycar.juti())
mycar.oder=2222
mycar.cheche()
还有就是修改的属性得放在实例之前,后面一定不行。。
2.通过方法修改属性的值
2020 Aodi A98
this car has 2222 miles on it !
就是再加一个方法,这个方法接受一个形参给mile,并将其存储到self.oder中,从而代替了原本的0 。。。
在红线处,我们调用update_oder(),并向他提供实参
可以对这种方法update_oder进行拓展,使其在修改时做一些额外的工作。
class Car():
def __init__(self,make,model,year):
self.make=make
self.model=model
self.year=year
self.oder=0
def juti(self):
che=str(self.year)+' '+self.make+' '+ self.model
return che.title()
def cheche(self):
print("this car has "+str(self.oder)+" miles on it !")
def update_oder(self,mile):
if mile>=self.oder:
self.oder=mile
else:
print('no no no !!!')
mycar=Car('aodi','a98',2020)
print(mycar.juti())
mycar.update_oder(-1)
mycar.cheche()
对输入的值进行判断if判断,不符合就禁止回拨
3.通过方法对属性的值进行递增
def zeng_oder(self,mile):
self.oder+=mile
接上面的代码,就很容易看出来。
习题:
# 9-4 就餐人数 : 在为完成练习9-1而编写的程序中, 添加一个名为number_served 的属性, 并将其默认值设置为0。
# 根据这个类创建一个名为restaurant 的实例; 打印有多少人在这家餐馆就餐过, 然后修改这个值并再次打印它。
# 添加一个名为set_number_served() 的方法, 它让你能够设置就餐人数。 调用这个方法并向它传递一个值, 然后再次打印这个值。
# 添加一个名为increment_number_served() 的方法, 它让你能够将就餐人数递增。 调用这个方法并向它传递一个这样的值:
# 你认为这家餐馆每天可能接待的就餐人数。
class Restaurant():
def __init__(self,restaurant_name,cuisine_type):
self.restaurant_name = restaurant_name
self.cuisine_type = cuisine_type
self.number_served = 1
def describe_restaurant(self):
print(self.restaurant_name)
print(self.cuisine_type)
def open_restaurant(self):
print('Restaurant is open')
def number_served_info(self):
print('[' + self.restaurant_name + '] 这家餐馆每天可能接待的就餐人数: ' + str(self.number_served))
print('来 [' + self.restaurant_name + '] 吃 [' + self.cuisine_type + '] 的人有:'+str(self.number_served)+' 人!')
def set_number_served(self,number_info):
self.number_served = number_info
def increment_number_served(self,name_add):
self.number_served += name_add
restaurant = Restaurant('紫光阁','北京菜')
restaurant.number_served = 30
restaurant.set_number_served(1)
restaurant.increment_number_served(100)
restaurant.increment_number_served(100)
restaurant.increment_number_served(100)
restaurant.increment_number_served(100)
restaurant.number_served_info()
9-5 尝试登录次数 : 在为完成练习9-3而编写的User 类中, 添加一个名为login_attempts 的属性。编写一个名为increment_login_attempts() 的方法,它将属性login_attempts 的值加1。 再编写一个名为reset_login_attempts() 的方法, 它将属性login_attempts 的值重置为0。 根据User 类创建一个实例, 再调用方法increment_login_attempts() 多次。 打印属性login_attempts 的值,确认它被正确地递增; 然后, 调用方法reset_login_attempts() , 并再次打印属性login_attempts 的值, 确认它被重置为0
class User():
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.login_attempts = 0
def describe_user(self):
print('用户名称为:' + self.first_name + self.last_name)
print('共登录用户量:(重置中……)\n'+str(self.login_attempts))
def greet_user(self):
print('你好! ' + self.first_name + self.last_name)
def increment_login_attempts(self,number):
self.login_attempts += number
print('共登录用户量:' + str(self.login_attempts))
def reset_login_attempts(self):
self.login_attempts = 0
user_a = User('Ma','Yun')
user_a.increment_login_attempts(1)
user_a.increment_login_attempts(1)
user_a.increment_login_attempts(1)
user_a.reset_login_attempts()
user_a.describe_user()
9.3 继承
编写类,并不是一定要从空白开始。如果要编写的类是另一个现成的版本,可以使用继承。
一个类继承另一个类时,它将自动获取另一个类的所有属性和方法;
原有的类称为父类新的类称为子类
9.3.1 子类的方法__init__()
在原本的Car类后面创建子类,例如添加下列代码
class Ele(Car):
def __init__(self,make,model,year):
super().__init__(make,model,year)
第一行:定义了子类Ele,定义子类,括号里必须有父类。
第二行:方法__init__()接受创造Car实例所需的信息
第三行:super()是一个特殊的函数。帮助python将子类和父类关联起来。让python调用Ele的父类的方法__init__(),让Elc实例包含父类的所有属性。
9.3.2 python2.7的继承
class Car(object)
def __init__(self,make,model,year):
--snip--
class Ele(Car)
def __init__(self,make,model,year)
super(Ele,self).__init__(make,model,year)
--snip--
函数super()需要两个实参:子类名和对象self。
在2.7中,请把父类括号加(object)
9.3.3 给子类定义属性和方法
可添加区分子类和父类所需的新属性和方法
class Ele(Car):
def __init__(self,make,model,year):
super().__init__(make,model,year)
self.battery_size=70
def describe_battery(self):
print('this is '+str(self.battery_size)+' -kwh battery')
mycar=Ele('baoma','model s',2021)
print(mycar.juti())
mycar.describe_battery()
在第四行,我们添加了新的属性,并将其设置为70
嗯。。刚开始对父类的代码咋弄都不对,发现因为方法juti后面忘记加()了,。。。。
9.3.4 重写父类的方法
对于父类的方法,只要不符合子类模拟的实物行为,都可以进行对其重写。
在子类中定义这样的方法,就是这个方法的名字要与父类的相同。
def aiqing(self):
print('qu ni ma de!')
在Car父类这样的用这样的方法,python将忽略Car中的方法aiqing(),转而进行代码。
9.3.5 将实例用作属性
在属性和方法清单及文件越来越长时,可能需要将类的一部分作为一个独立的类提取出来。
可以将大型类拆分为多个协同工作的小类
class Batter():
def __init__(self,battery_size=70):
self.battery_size=battery_size
def describe_battery(self):
print('this car is '+str(self.battery_size)+' -kwh battery')
class Ele(Car):
def __init__(self,make,model,year):
super.__init__(make,model,year)
self.battery=Batter()
mycar=Ele('benchi','model',2021)
mycar.battery.describe_battery()
class Car():的代码省略了。。最后一行让python在mycar中查找属性battery,并对存储在该属性的Battery实例调用方法describe_battery()。
9.3.6 模拟实物
就是要找出高效率的代码
9-7 管理员 : 管理员是一种特殊的用户。 编写一个名为Admin 的类, 让它继承你为完成练习9-3或练习9-5而编写的User 类。
添加一个名为privileges 的属性, 用于存储一个由字符串(如"can add post" 、 "can delete post" 、 "can ban user" 等)组成的列表。 编写一个名为show_privileges() 的方法, 它显示管理员的权限。 创建一个Admin 实例, 并调用这个方法
class User():
def __init__(self, first_name,last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print('用户名称为:' + self.first_name + self.last_name)
def greet_user(self):
print('你好! ' + self.first_name + self.last_name)
class Admin(User):
def __init__(self,first_name,last_name):
super().__init__(first_name,last_name)
self.privileges=['can add post','can del post','can ban user ']
def show_privileges(self):
for i in self.privileges:
print('管理员有' + i)
admin=Admin('ma','yun')
admin.show_privileges()
9-8 权限 : 编写一个名为Privileges 的类, 它只有一个属性——privileges , 其中存储了练习9-7 所说的字符串列表。
将方法show_privileges() 移到这个类中。 在Admin 类中, 将一个Privileges 实例用作其属性。
创建一个Admin 实例, 并使用方法show_privileges() 来显示其权限。
class User():
def __init__(self, first_name,last_name):
self.first_name = first_name
self.last_name = last_name
def describe_user(self):
print('用户名称为:' + self.first_name + self.last_name)
def greet_user(self):
print('你好! ' + self.first_name + self.last_name)
class Admin(User):
def __init__(self,first_name,last_name):
super().__init__(first_name,last_name)
self.b = Privileges()
class Privileges():
def __init__(self):
self.privileges = ['can add post','can del post','can ban user']
def show_privileges(self):
for i in self.privileges:
print("管理员权限有:" + i)
Admin1 = Admin('Ma','Yun')
Admin1.b.show_privileges()
倒数第二行先创建Admin的实例,然后最后一行根据Admin的类找b的属性,然后b属性定位到P的类中的show_privileges()方法,然后打印
9-9的那一题干了半小时多。。迷了
9.4 导入类
python允许将类存储在模块中,然后i在主程序中导入模块
9.4.1 导入单个类
两个文件,第二个文件用来对类调用
导入类时一种有效的编程方式。通过导入,让代码变得整洁,这样就会专注于主程序的高级逻辑了
9.4.2 在一个模块中存储多个类
就是导入子类的就行了,之前有那个Car,Ele,然后导入子类,进行编码就行了。
9.4.3 从一个模块中导入多个类
可根据在程序文件中导入任意数量的类。
导入多个模块,用逗号分开。
9.4.4 导入整个模块
直接就文件名(不带拓展名)
9.4.5 在一个模块中导入另一个模块
例如文件有个mycar.py和bigcar.py
在mycar文件中调用了类Car
在big car 中就可以用mycar文件中的类Car来导入子类
...对bigcar 描述....
from car import Car
from mycar import Ele
9.4.6 自定义工作流程
先找编写出可行代码的方式,再让代码变得有序
9.5 python标准库
python标准库是一组模块,安装好的。可以在首行模块中导入类,使程序更加简化。例如空字典的模块
from collections import OrderedDict
myzidian=OrderedDict()
#下面就可以根据键-值来的生成字典
还有随机模块的调用
from random import randint
随机数的调用
from random import randint
class Die():
def __init__(self):
self.sides = 6
def roll_die(self):
self.sides = randint(1, 6)
print(self.sides)
die = Die()
print("----------6 sides-------------")
for i in range(10):
die.roll_die()
尝试把6、7行一句话,结果发现不可以,那就可能是语法错误,不能这样做。。。
9.6 类编码风格
类命名采用骆驼命名法,每个单词的首个字母大写,并且不使用下划线。实例名和模块名都采用小写,并且单词之间加下划线
对于类,应该在类定义后面包含一个文档字符串。简述其类的功能。
每个模块也都应该包含一个文档字符串,对其类可用于做什么进行描述。
同时导入模块(自己写的、标准库的),需要先导入标准库的,然后添加空行再导入自己的。
第十章 文件和异常
异常:python创建的特殊对象,用于管理程序运行时出现的错误
10.1 从文件中读取数据
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,可以一次性读取文件的全部内容,也可以每一次一行的方式逐步读取。
10.1.1 读取整个文件
这种方法得在同一文件夹下,我把txt文件命名为001.txt
要以任何方式使用文件--无论是仅仅打印的内容,都得先打开文件,才能访问它。
函数open()接受一个参数:打开文件的名称。python会在当前执行的文件的所在的目录中查找指定文件。函数open()返回一个表示文件的对象。例如上面open('001.txt')返回的就是一个表示文件001.txt的对象,并将这个对象存储在后面要使用的变量中
关键字with在不需要访问文件将其关闭。知道用open函数,没有调用close函数,如果添加close函数,这样做可能会导致存在文件的bug,导致close函数语句未执行,文件不会关闭。这样做会导致数据丢失或受损如果较早的调用close函数,关闭而导致无法访问。
所以只管打开,用关键字with后,python会在合适的时候将其自动关闭。
方法read()读取这个文件的全部内容,并将其存储在变量contents中。
多一个空行???
通过百度知道read()在到达文件末尾返回一个空字符串,而将这个空字符串显示出来就是一个空行,删除空行,用rstrip()去除末尾的空白的方法。
print(contents.strip())
10.1.2 文件路径
python只会在当前文件夹中查找,如果在子文件夹中,就不行,要让python打开不与程序文件位置位于同一目录中的文件,需要提供文件路径让python去找到系统的特定位置去查找。
相对路径来打开文件,路径中使用反斜杠\ 有时候很迷。。win下使用\ linux和os x中使用/
也可以用绝对文件路径,在相对路径不行的情况下。
对于python来说,反斜杠被视为转移标记,,为了确保万无一失,应以原始字符串的方式指定路径,即在开头的单引号前加r
不加r会报错
Traceback (most recent call last):
File "新建文本文档.py", line 1, in <module>
with open('D:\python日常\好家伙txt\001.txt')as file_object:
OSError: [Errno 22] Invalid argument: 'D:\\python日常\\好家伙txt\x01.txt'
所以养成习惯吧。。2333
10.1 .3 逐行提取
读取文件时,通常需要检查其中的每一行;要以每次一行的方式检查文件,可对文件对象使用for循环。
为啥有空白呢?
因为在文件中,每行的末尾都有一个看不见的换行符,而print会加上这些换行符,因此**每行末尾都有两个换行符,一个文件,一个来自print语句。要消除就用首位全消的rstrip()方法啦。。
10.1.4 创建一个包含文件各行内容的列表
如果要在with代码块外访问文件内容,可在with代码块内将文件的各行存储在一个列表中,并在with代码外使用该列表:可以立即处理文件的各个部分,也可以推迟到程序后面处理
readlines()从文件中读取每一行,并将其存储在一个列表中;接下来,列表被存储到lines中,在with代码块外,依然可以使用这个变量。在for语句中打印lines各行。
10.1.5 使用文件的内容
将文件存储到内存中,就可以用任何方式使用这些数据了。
进阶:首先创建一个空的字符串,它包含文件中存储的所有数字,且没有空格。
filename='001.txt'
with open(filename) as wenjian:
lines=wenjian.readlines()
string=''
for line in lines:
string+=line.rstrip()
print(string)
print(len(string))
rstrip()方法是将末尾的换行符删除,(len计算包括数字空格)
在string存储的字符串中,包含原来位于每行左边的空格,为删除这些空格,直接使用方法strip()删除开头末尾所有空格.
string+=line.strip()
ps:对于读取文本时候,python将其中的所有文本都解读为字符串,如果读取的是数字,并要将其作为数值使用,就得使用函数int()将其转化为整数,或转化为浮点数flaot()
10.1.6 包含一百万位的大型文件
使用方括号分割其中的元素,假如保留30位
print(string[:30]+'...')
python没有任何限制,只要系统内存够,2333333
10.1.7 圆周率中包含你的生日吗
filename='001.txt'
with open(filename) as wenjian:
lines=wenjian.readlines()
string=''
for line in lines:
string+=line.strip()
birthday=input('输入你的生日,仅限数字,不带符号空格!\n')
if birthday in string:
print('yes,you can see')
else:
print('拉倒吧!!!')
习题:
f_name = '001.txt'
with open(f_name) as f_name1:
print('_________"1"___________')
print(f_name1.read().rstrip())#读取整个文件
with open(f_name) as f_name1:
print('_________"2"___________')
for i in f_name1:
print(i.rstrip())#打印时遍历文件对象
with open(f_name) as f_name1:
print('_________"3"___________')
lines = f_name1.readlines()
for i in lines:
print(i.rstrip())#打印时将各行存储在一个列表中,再打印。。。
10.2 写入文件
保存数据最简单的方式之一是将其写入到文件中。通过将输入写入文件,即便关闭包含的进程输出的终端窗口,这些输出依旧存在。
10.2.1 写入空文件
filename='001.txt'
with open(filename,'w') as xie:
xie.write('gggggggggggg')
在这个示例中,调用open()提供了两个实参,第一个是打开文件的名臣001.txt,第二个实参是("w"),它告诉python,我们要以写入模式打开这个文件
读取模式('r') 写入模式('w') 附加模式('a')
或者读加写的模式('r+'),如果省略这些模式参数,默认只读模式打开文件
如果写入的文件不存在,会自动创建;如果有文件,并且用模式('w')进行写入会清除原来的内容。
python只能将字符串写入到文本文件,要是数值数据存储到文本,必须使用str()将其转化为字符串格式。
10.2.2 写入多行
函数write()不会在末尾加入换行符,就用\n
还可以使用空格、制表符\t和空行来设置这些输出
10.2.3 附加文件
如果要给文件添加内容,但又不是覆盖原有的内容,可以附加模式打开文件。以附加模式打开文件,python不会在返回文件对象前清空文件,但写入到文件的行都被添加到文件末尾,如果指定文件不存在,python会自动创建一个空文件。
打开文件时指定实参'a',将内容附加到末尾,可以用换行,使其更加简洁。
最终结果,是文件原本的内容还在,后面是新的添加的。
它与写入模式不同,写入模式一开启,就会清除原本文本文件的内容。
truncate()是清空当前的文本内容
写和读的模式(即w和r)用r+,但是他也会向w那样,会清除文件的内容而继续的写。。。
10.3 异常
python使用被称为异常的特殊对象来管理程序执行期间发生的错误。每当发生让python不知所措的错误时,都会创建一个异常对象。
异常是使用try-except代码块处理的。该代码块让python执行指定的操作,同时告诉python发生异常怎么办。使用该模块,即便出现异常,程序也会继续运行
10.3.1 处理ZeroDivisionError异常
任何数都不能除以0,不然会报错
下面告诉python,出现这种错误怎么办。
10.3.2 使用try-except代码块
可编写该代码块来处理可能发生的异常。
如果try中的代码块运行没问题,会跳过except代码块。反之,出现错误,python就会查找这样的except代码块,并运行其中的代码。这样看到的就不是tracrback了。
10.3.3 使用异常避免崩溃
如果程序还没完成工作,妥善的处理代码很重要,以至于不崩溃。
print('给我两个数字,我让它们两个相除')
print('按q建退出')
while True:
f_num=input('第一个数字: ')
if f_num=='q':
break
s_num=input('第二个数字: ')
if s_num=='q':
break
try:
answer=int(f_num)/int(s_num)
except ZeroDivisionError:
print('不会吧,不会吧,2333333')
else:
print(answer)
如果不添加try-except,else,就会报错
10.3.4 else代码块
按照上面的代码,我们知道try-except提高这个程序抵御错误的能力。
依赖于try代码块成功的代码都应放到else代码块中。就是要考虑到代码成功不成功的问题,所以才会有else,如果成功,就会忽略except的代码,接着执行else的代码,不成功就是执行except的代码。
10.3.5 处理FileNoteFoundError异常
except
Traceback (most recent call last):
File "新建文本文档.py", line 2, in <module>
with open(filename) as weijian:
FileNotFoundError: [Errno 2] No such file or directory: '002.txt'
上面是未发现文件的报错
使用try-ecpect模块就行了
10.3.6 分析文本
对包含字符串的变量,采用方法split()根据字符串创建一个字典。
方法split()以空格为分割符将字符串分拆成多个部分,并将这些部分都存储到一个列表中。结果是一个包含字符串中所有单词的列表,虽然有些单词可能有标点。
对于上图,要把filename的路径正确,然后输入几个单词,进行测试。因为try执行成功,没有所谓的FileNotFounfError的报错,就进行else的单词计数。
10.3.7 使用多个文件
为了简约,可以把大部分代码移入到count_words()函数中,使对多本书分析更容易
def count_words(filename):
try:
with open(filename) as wenjian:
neirong=wenjian.read()
except FileNotFoundError:
print('sorry,this '+filename+'not found youe said')
else:
words=neirong.split()
num_words=len(words)
print('the file about '+str(num_words)+' words!')
filename='001.txt'
count_words(filename )
同样,真央就可以进行多个文件的计数。
只需要在第11行,添加一个列表。['001.txt','002.txt']
不存在的文件也没有事,因为用了try-except模块,会对错误进行处理。
10.3.8 失败一生不吭
python有一个pass语句,可以在代码块中使用它来让python什么都不做
就是把except会出现的报错内容换成pass
except FileNotFoundError:
pass
不会出现traceback,也不会有任何输出。
pass还充当了占位符,提醒在程序的某个地方什么都没做,并且以后要在这里做
10.3.9 决定报告哪些错误
traceback
拓展:count()来确定特定的单词或短语在字符串中出现了多少次,还有上面的清除文件内容的truncate()函数,在用count函数时,尽量把英文全部变成小写lower(),这样会更加准确,不会因为大小写而出现不准确
filename='001.txt'
with open(filename) as wenjian:
neirong=wenjian.read()
print(neirong.lower().count('chen'))
10.4 存储数据
一种简单的方式手机用模块json来存储数据
这种格式并非python专用的,但是很易于学习,也很有用。
json格式最初是javascript开发的,但随后变成常见的一种格式
10.4.1 使用json.dump和json.load()
函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象。
使用json.dump()来存储数字列表
import json
num=[2,3,4,6,7,8,9]
filename='001.json'
with open(filename,'w') as wenjian:
json.dump(num,wenjian)
先导入模块json,再创建一个数字列表。在第三行,指定要将内容存储在的文件,通常使用文件拓展名.json来指出文件储存的数据为JSON格式。接下来就是写入文件内容,使用函数json.dump()将数字列表存储在文件001.json
使用json.load()将这个列表读取到内存中
import json
filename='001.json'
with open(filename) as wenjian:
num=json.load(wenjian)
print(num)
使用函数json.load()加载存储在001.json的信息,并将存储到变量num中,
10.4.2 保存和读取用户生成的数据
import json
username=input('what your name?\n')
filename='001.json'
with open(filename,'w') as wenjian:
json.dump(username,wenjian)#对于这个函数,前一个参数是要存储的内容,后一个是储存在那
print('yes,'+username+' you will record!~')
再编写一个程序,向存储的用户问候
在第四行使用json.load()将存储在001.json的信息读取到变量中。
要将这两个程序连载一起,一提一问,使用try-ecxept,和else代码块
10.4.3重构
将代码划分为一系列完成具体工作的函数的过程称为重构
重构让代码更清晰、易理解、易拓展
重构,可将其大部分罗技放到一个或多个函数中。
import json
def greet():
filename='001.json'
try:
with open(filename) as wenjian:
username=json.load(wenjian)
except FileNotFoundError:
username=input('what you name?\n')
with open(filename,'w') as wenjian:
json.dump(username,wenjian)
print('welcome '+username+' join python')
else:
print('welcome back '+username+'!')
greet()
将所有代码都放到了greet()函数中。
还可以将里面的另一个代码块取出来等
总的来说就是把一个def内容分工成多个def,使得代码块更清晰、易懂。。。
嗯。。。感觉代码理解方面,还是欠缺,得刷题才有可能解决这个弊端。。
别人都在不停的努力,自己又怎么会停