本系列为Python编程基础的学习笔记。
本文主要介绍Python的类、文件、异常的相关基础知识。

一、类

1.1 创建类

类的定义
类的格式大致如下:

class 类名:
    类文档字符串
    
    def init(self, 形参1, 形参2, ……):
        方法文档字符串
        self.形参1 = 形参1
        self.形参2 = 形参2
        ……
    
    def 方法名(self):
        方法文档字符串
        方法语句

例如:

1
2
3
4
5
6
7
8
9
10
11
12
class Student:
"""This is a student class"""

def __init__(self, s_id, s_name):
"""This is a init function"""
self.s_id = s_id
self.s_name = s_name

def information(self):
"""This is a print function"""
print("ID: " + self.s_id)
print("Name: " + self.s_name)

相关要点
在Python中,首字母大写的名称指的是类;
类中的函数称为方法,有关函数的一切操作都适用于方法;
默认方法init():一个特殊方法,能对实例进行初始化,开头和末尾各有两个下划线,原因是避免默认方法与普通方法发生名称冲突;
每个类中的方法的形参都应包含self,且必须位于其它形参的前面;
每个与类相关联的方法调用都自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法;
以self为前缀的变量可提供给类中的所有方法使用,还可通过类的任何实例来访问这些变量,可通过实例访问的变量称为属性。

1.2 创建实例

类描述了如何创建一个实例,根据类来创建一个具体的对象被称为实例化。
格式:

实例名 = 类名(实参1, 实参2, ……)

例如,可对上述Student类进行实例化得到实例student:

1
student = Student('1', 'test')

其中,实例self在方法调用时已经被自动传递。

访问属性
访问实例的属性可采用句点表示法,格式:

实例名.属性名

例如,可访问上述实例student中的两个属性:

1
2
print(student.s_id)
print(student.s_name)

运行结果为:
1
test

调用方法
调用实例的任何方法可采用句点表示法,格式:

实例名.方法名()

例如,可访问上述实例student中的方法:

1
student.information()

运行结果为:
ID: 1
Name: test

创建多个实例
可按实际需求根据一个类创建任意数量的实例,条件是将每个实例都存储在不同的变量当中,或占用列表或字典的不同位置。
例如:

1
2
student1 = Student('1', 'test')
student2 = Student('2', 'TEST')

1.3 使用类和实例

给属性指定默认值
类的每个属性必须有默认值。可以在默认方法__init__中指定默认值,指定默认值的属性无需包含为它提供初始值的形参。

修改属性的值
直接修改属性的值:
使用句点访问法直接访问并修改属性的值,格式:

实例名.属性名 = 新值

通过方法修改属性的值
在类的内部定义修改方法,通过将新值传递给修改方法,在实例内部完成修改。

1.4 继承

继承
一个类继承另一个类时,它将自动获得另一个类的所有属性和方法;原有的类称为父类,新类称为子类。
子类在继承父类所有属性和方法的同时,还可以定义自己的属性和方法。

创建子类
创建子类时,父类必须包含在当前文件中,且位于子类的前面;
定义子类时,必须在其括号内指定父类的名称;
父类也称为超类,使用super()函数将父类与子类关联起来,让子类调用父类的__init__方法完成父类属性的初始化;
创建子类实例时,Python首先需要给父类的所有属性赋值。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student:
"""This is a father class"""

def __init__(self, s_id, s_name):
"""This is a init function"""
self.s_id = s_id
self.s_name = s_name

def information(self):
"""This is a print function"""
print("ID: " + self.s_id)
print("Name: " + self.s_name)


class CollegeStudent(Student):
"""This is a son class"""

def __init__(self, s_id, s_name):
"""This is a init function"""
super().__init__(s_id, s_name)


student1 = CollegeStudent('1', 'test')
student1.information()

运行结果为:
ID: 1
Name: test

给子类定义属性和方法
可以在子类中定义自己的属性和方法,例如上述子类CollegeStudent可定义为:

1
2
3
4
5
6
7
8
9
10
11
class CollegeStudent(Student):
"""This is a son class"""

def __init__(self, s_id, s_name, s_phone):
"""This is a init function"""
super().__init__(s_id, s_name)
self.s_phone = s_phone

def get_phone(self):
"""This is a new function"""
print("Phone: " + self.s_phone)

重写父类方法
当父类的方法不符合子类的行为时,可以在子类中重写父类的方法。
方式:在子类中定义一个与要重写的父类方法同名的方法。
例如,可以在子类CollegeStudent中对父类Student的information()方法进行重写:

1
2
3
4
5
6
class CollegeStudent(Student):
--snip--

def information(self):
"""This is a print function"""
print("The function have been changed!")

将实例用作属性
可以将一个类的实例用作另一个类中的属性。基于此可以将大型类拆分为多个协同工作的小类,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student:
--snip--


class Grade:
--snip--


class CollegeStudent(Student):
--snip--

def __init__(......):
super().__init__(......)
self.grade = Grade() #新建Grade实例并存储在属性self.grade中

1.5 导入类

Python允许将类存储在模块中,然后在主程序中导入所需的模块。

导入单个类
例如,将类Student存储在student.py模块中:

1
2
3
4
5
"""这里是模块级的文档字符串,每个模块都应编写对应的文档字符串"""

class Student:
"""这是Student类的文档字符串"""
--snip--

然后在主程序文件rea_student.py中导入该模块:

1
from student import Student

在一个模块存储多个类
可以根据实际需要,在一个模块中存储任意数量的类。例如student.py模块可为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""这里是模块级的文档字符串,每个模块都应编写对应的文档字符串"""

class Student:
"""这是Student类的文档字符串"""
--snip--


class Book:
"""这是Book类的文档字符串"""
--snip--


class ClaRoom:
"""这是ClaRoom类的文档字符串"""
--snip--

从一个模块中导入多个类
可以根据实际需要在程序文件中导入模块中的多个类,例如:

1
from student import Student, Book, ClaRoom

导入整个模块(推荐)
可以根据实际需要在程序文件中导入整个模块,然后通过句点表示法访问具体的类,例如:

1
2
3
import student

student.Student

导入模块中的所有类(不推荐)
可以根据实际需要在程序文件中导入模块中的所有类,例如:

1
from student import *

在一个模块中导入另一个模块
当一个模块中的类依赖于另一个模块中的类时,可以在前一个模块中导入必要的类。例如:
模块Student.py:

1
2
3
4
5
6
"""这里是模块级的文档字符串,每个模块都应编写对应的文档字符串"""

class Student:
"""这是Student类的文档字符串"""
--snip--

模块CollegeStudent.py:

1
2
3
4
5
6
7
8
"""这里是模块级的文档字符串,每个模块都应编写对应的文档字符串"""

from student import Student

class CollegeStudent(Student):
"""这是CollegeStudent类的文档字符串"""
--snip--

1.6 类的编码规范

类名采用驼峰命名法,即每个单词的首字母大写,不使用下划线;
实例名和模块名均采用小写,单词之间使用下划线;
类的定义后面应当紧跟一个文档字符串,用以说明类的功能和格式描述;
模块的开头应当包含一个文档字符串,用以说明模块中的类功能描述;
在类中,使用一个空行分隔方法;
在模块中,使用两个空行来分隔类;
先导入标准库模块,添加一个空行,再导入自定义模块。

二、文件

2.1 读取文件

读取整个文件
open()函数:接收一个参数(即文件名),找到指定文件后,返回一个表示该文件的对象。
read()方法:读取并返回对象所指定文件的全部内容。
关键字with:不再需要访问文件后自动将其关闭(避免人为close()关闭带来的种种错误)。
格式:

with open(文件名) as 对象名:
    变量名 = 对象名.read()

例如:

1
2
with open('test.txt') as file_object:
contents = file_object.read()

运行后文件test.txt中的所有内容将被存储到变量contents中。

注意:read()到达文件末尾时将返回一个空字符串,打印时该空字符串会打印为空行,利用rstrip()方法可在打印时去掉对应的空行。

文件路径
要让Python打开一个不与程序文件同在一个目录的文件时,需要提供文件路径。
相对文件路径:文件存储位置相对于当前程序文件位置的路径表示;
绝对文件路径:文件在计算机上的准确存储位置,与当前程序文件位置无关。
注意:当绝对路径较长时,可将其保存在单独的一个变量中再进行传递使用。

逐行读取
采用上述open()函数与for循环实现,格式:

with open(文件名) as 对象名:
    for line in 对象名:

例如:

1
2
3
with open('test.txt') as file_object:
for line in file_object:
……

运行后文件test.txt中的内容将被逐行读取并存储到变量line中。

注意:每一行末尾都存在一个看不见的换行符,打印时该换行符会打印为空行,利用rstrip()方法可在打印时去掉对应的空行。

创建包含文件各行内容的列表
关键字with使得open()返回的文件对象只在with代码块中有效,使用列表存储可以使得文件内容能在代码块外使用。
readlines()方法:从对象所指定文件中读取每一行,并存储到列表当中,返回列表。
格式:

with open(文件名) as 对象名:
    变量名 = 对象名.readlines()

例如:

1
2
with open('test.txt') as file_object:
lines = file_object.readlines()

运行后文件test.txt中的内容将被逐行读取并生成列表,存储到变量lines中。

注意:在读取文本文件时,返回的结果均为字符串。如果读取的是数字,需要当做数值使用时,必须使用int()函数或float()函数来转换为整数或浮点数。

2.2 写入文件

写入空文件
open()函数:需接收两个参数(文件名和模式参数),找到(或创建)指定文件后,返回一个表示该文件的对象。
write()方法:将一个字符串写入到对象所指定文件当中。
模式参数:

‘r’:读取模式
‘w’:写入模式(完全清除原有内容)
‘a’:附加模式(完全保留原有内容)
‘r+’:读取和写入模式(从头开始逐字节覆盖原有内容)
未指定模式参数时默认为只读模式

格式:

with open(文件名, 模式参数) as 对象名:
    对象名.write(字符串)

例如:

1
2
with open('test.txt', 'w') as file_object:
file_object.write('This is a test.')

运行后文件test.txt中原有的内容将被清除,并被写入新的字符串。

写入多行
可在使用write()方法写入的字符串中添加换行符(\n)来进行多行写入。
除此之外,同样可以使用空格、制表符、空行等来进行写入格式的设置。

注意:在写入文本文件时,只能写入字符串。如果写入的是数值,必须先使用str()函数转换为字符串。

2.3 数据存储

JSON - JavaScript Object Notation,JSON格式文件拓展名为.json

json.dump()和json.load()
json.dump()函数:接收两个参数,即要存储的数据和存储数据的文件对象。
json.load()函数:接收一个参数,即要读取数据的文件对象。
例如:

1
2
3
4
5
6
import json

message = "Hello Python!"

with open('test.txt', 'w') as file_object:
json.dump(message, file_object)

运行后数据将被存储到文件当中。

1
2
3
4
5
6
import json

with open('test.txt') as file_object:
message = json.load(file_object)

print(message)

运行后文件数据将被读取到变量message中并打印输出。

重构
将能够正常运行的代码做进一步的改进——将代码划分为一系列完成具体工作的函数,这样的过程被称为重构。

三、异常

3.1 异常

异常:用来管理程序执行期间发生的错误的特殊对象。
每当程序发生不知所措的错误时,都会创建一个异常对象。
发生异常时,若存在异常处理代码,则程序继续执行,若不存在异常处理代码,程序停止并显示一个traceback。
异常是使用try-except代码块来进行处理的。

3.2 常见异常

ZeroDivisionError异常
除数为0时将指出ZeroDivisionError异常。

FileNotFoundError异常
文件无法打开时将指出FileNotFoundError异常。

3.3 try-except代码块

使用try尝试运行代码,产生错误时查找except代码块并按指定异常措施解决异常。例如:

1
2
3
4
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide by zero!")

运行后将输出友好的错误消息而不是traceback。
也可将错误消息更改为pass语句,不做任何输出,也不会出现traceback,一声不吭,例如:

1
2
3
……
except ZeroDivisionError:
pass

注意:只有可能引发异常的代码才需要放在try代码块中。

3.4 else代码块

如果某些代码的执行需要依赖于try代码块的成功执行,则这些代码块应该放于else代码块中,例如:

1
2
3
4
5
6
try:
a = b / c
except ZeroDivisionError:
print("You can't divide by zero!")
else:
print(a)

运行时,只有当a = b / c的计算无异常时,才能够执行print(a)输出结果。

3.5 文本分析

split()方法:以空格为分隔符将字符串拆分为多个部分,并将这些部分存储到一个列表中。
例如:

1
2
test = "Hello Python"
print(test.split())

运行结果为:
[‘Hello’, ‘Python’]

之后,可以利用列表求出文本的单词数量等特征。

(未完待续…)

评论区 (输入正确的邮箱可以收到回复哦!网址可选)