Python高级基础
1.文件
1.1文件操作步骤
-
打开文件
-
读写等操作
-
关闭文件
1.1.1文件操作的函数/方法
序号 | 函数/方法 | 说明 |
---|---|---|
01 | open | 打开文件,并且返回文件操作对象 |
02 | read | 将文件内容读取到内存 |
03 | write | 将指定内容写入文件 |
04 | close | 关闭文件 |
-
open
函数负责打开文件,并且返回文件对象 -
read
/write
/close
三个方法都需要通过 文件对象 来调用 -
open
函数的第一个参数是要打开的文件名(文件名区分大小写)-
如果文件 存在,返回 文件操作对象
-
如果文件 不存在,会 抛出异常
-
-
read
方法可以一次性 读入 并 返回 文件的 所有内容 -
close
方法负责 关闭文件
1)打开/写入文件
在Python中,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件,语法如下:
open(name, mode)
name:是要打开目标文件名的字符串(可以包含文件所在的具体路径)
mode:设置打开文件的模式(访问模式):只读、写入、追加等
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常 |
w | 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a | 以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常 |
w+ | 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a+ | 以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
提示
-
频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以 只读、只写 的方式来操作文件
打开文件并进行写入示例
# 打开文件 f = open("README", "w") f.write("hello python!\n") f.write("今天天气真好") # 关闭文件 f.close()
2)读取文件
1. read()
文件对象.read(num)
num表示要从文件中读取的数据的长度(单位都是字节),如果没有传入num,那么就表示读取文件的所有数据
一次性读取文件内容
# 1. 打开 - 文件名需要注意大小写 file = open("README") # 2. 读取 text = file.read() print(text) # 3. 关闭 file.close()
注意:read
方法执行后,会把 文件指针 移动到 文件的末尾
文件指针
文件指针 标记 从哪个位置开始读取数据
第一次打开 文件时,通常 文件指针会指向文件的开始位置
当执行了
read
方法后,文件指针 会移动到 读取内容的末尾
默认情况下会移动到 文件末尾
2. readlines()
readlines可以按照行的方式把整个文件中的内容按行进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素
fp = open("E:\student.txt", "r") result = fp.readlines() print(result) # ['aaa\n', 'bbb\n', 'ccc\n', 'ddd'] fp.close()
3. readline()
-
readline
方法可以一次读取一行内容 -
方法执行后,会把 文件指针 移动到下一行,准备再次读取,适用于读取大文件
读取大文件的正确姿势
# 打开文件 file = open("README") while True: # 读取一行内容 text = file.readline() # 判断是否读到内容 if not text: break # 每读取一行的末尾已经有了一个 `\n` print(text, end="") # 关闭文件 file.close()
1.1.2 r+ 和 w+ 和 a+ 区别
""" 1. r+ 和 w+ a+区别 2. 文件指针对数据读取的影响 3. test.txt已存在并且有数据,test1.txt不存在 """ # r+: 文件不存在则报错,文件指针在开头,能够读出数据 # f = open('test1.txt', 'r+') # f = open('test.txt', 'r+') # w+:文件不存在会新建文件,文件指针在开头,读数据时会用新内容覆盖原内容 # f = open('test1.txt', 'w+') # f = open('test.txt', 'w+') # a+:文件不存在会新建文件,文件指针在末尾,不能够读出数据 f = open('test1.txt', 'a+') f = open('test.txt', 'a+') con = f.read() print(con) f.close()
1.1.3 seek()
作用:用来移动文件指针
语法如下:
文件对象.seek(偏移量, 起始位置)
起始位置:
0:文件开头
1:当前位置
2:文件结尾
# r 改变文件指针位置:改变读取数据开始位置或把文件指针放在末尾(无法读取数据) fp = open('E:/student.txt', 'r') # 改变文件指针,读取改变后的数据 fp.seek(6, 0) # 文件指针放在末尾(无法读取数据) # fp.seek(0, 2) con = fp.read() print(con) fp.close()
1.2 文件备份
需求:用户输入当前目录下任意文件名,程序完成对该文件的备份功能(备份文件名为xx[备份]后缀,例如:test[备份].txt)
1.2.1步骤
-
接收用户输入的文件名
-
规划备份文件名
-
备份文件写入数据
1.2.2代码实现
# 1.接收用户输入目标文件 old_name = input('请输入你要备份的文件名:') # 2.规划备份文件的名字 # 2.1提取目标文件后缀 index = old_name.rfind('.') # 2.2有效文件才备份 if index > 0: postfix = old_name[index:] else: print("输入文件名无效!") # 2.3组织新文件名:旧文件名 + [备份] + 后缀 new_name = old_name[:index] + '[备份]' + postfix print(new_name) # 3.备份文件写入数据(数据和原文件一样) # 3.1打开文件 old_fp = open(old_name, 'rb') new_fp = open(new_name, 'wb') # 3.2将原文件数据写入备份文件 while True: con = old_fp.read(1024) if len(con) == 0: break new_fp.write(con) # 3.3关闭文件 old_fp.close() new_fp.close()
1.3文件和文件夹的操作
在Python中文件和文件夹的操作要借助os模块里面的相关功能,具体步骤如下:
-
导入os模块
import os
-
使用os模块相关功能
os.函数名()
1.3.1文件重命名
os.rename(目标文件名,新文件名)
1.3.2删除文件
os.remove(目标文件名)
# 导入模块os import os # 1.rename():重命名 os.rename('test.txt', 'lyc.txt') # 2.remove():删除文件 os.remove('test[备份].txt')
1.3.3创建文件夹
os.mkdir(文件夹名字)
1.3.4删除文件夹
os.rmdir(文件夹名字)
1.3.5获取当前目录
os.getcwd()
1.3.6改变默认目录
os.chdir(目录)
1.3.7获取目录列表
os.listdir(目录)
# 导入模块os import os # 1.mkdir():创建文件夹 # os.mkdir('lyc') # 2.rmdir():删除文件夹 # os.rmdir('lyc') # 3.getcwd():获取当前目录 path = os.getcwd() print(path) # 4.chdir():改变默认目录路径 # 需求:在lyc文件夹里创建文件夹aa # os.mkdir('lyc') # os.chdir('lyc') # os.mkdir('aa') # 5.listdir():获取目录列表 print(os.listdir('lyc')) # 6.rename():重命名文件夹 os.rename('lyc', 'bb')
1.3.8应用案例
需求:批量修改文件名,既可添加指定字符串,又能删除指定字符串
-
步骤
-
设置添加删除字符串的标识
-
获取指定目录的所有文件
-
将原有文件名添加/删除指定字符串,构造新名字
-
os.rename()
重命名
-
-
代码
# 需求1:把code文件夹所有文件重命名 Python_xxxx import os # 设置重命名标识:如果flag取值为1则添加指定字符,flag取值为2则删除指定字符 flag = 1 # 获取指定目录 dir_name = './' # 获取指定目录的文件列表 file_list = os.listdir(dir_name) # 遍历文件列表内的文件 for name in file_list: # 添加指定字符 if flag == 1: new_name = 'Python_' + name # 删除指定字符 elif flag == 2: num = len('Python_') new_name = name[num:] # 打印新文件名,测试程序正确性 print(new_name) # 重命名 os.rename(dir_name+name,dir_name+new_name)
2.面向对象
面向对象就是将编程当成一个是一个事物,对外界来说,事物是直接食用的,不用去管他内部的情况。而编程就是设置事物能够做什么事
2.1类和对象
在面向对象编程过程中,有两个重要组成部分:类和对象
类和对象关系:用类去创建一个对象
2.1.1类
类是一系列具有相同特征和行为的事物的统称,是一个抽象概念,不是真实存在的事物
-
特征即是属性
-
行为即是方法
2.1.2对象
对象是创建出来的真实存在的事物
2.2面向对象实现方法
2.2.1定义类
Python2
中类分为:经典类和新式类
-
语法
class 类名(): 代码 .......
注意:类名要满足标识符的命名规则,同时遵循大驼峰命名习惯
2.2.2创建对象
对象又名实例
-
语法
对象名 = 类名()
-
体验
# 需求:洗衣机 功能:洗衣服 # 1.定义洗衣机类 class Washer(): def wash(self): print("洗衣服") # 2.创建对象 haier = Washer() # 实例方法 对象名.wash() haier.wash()
2.2.3self
self指的是调用该函数的对象
# 需求:洗衣机 功能:洗衣服 # 1.定义洗衣机类 class Washer(): def wash(self): print("我会洗衣服") # <__main__.Washer object at 0x000001EAE7699A58> print(self) # 2.创建对象 haier = Washer() # <__main__.Washer object at 0x000001EAE7699A58> print(haier) haier.wash()
2.3添加和获取对象属性
属性即是特征,比如:洗衣机的宽度、高度、重量...
对象属性既可以是在类外面添加和获取,也能在类里面添加和获取
2.3..1类外面添加对象属性
-
语法
对象名.属性名 = 值
-
体验
haier.width = 500 haier.height = 800
2.3.2类外面获取对象属性
-
语法
对象名.属性名
-
体验
print(f'haier洗衣机的宽度是{haier.width}') print(f'haier洗衣机的高度是{haier.height}')
2.4类里面获取对象属性
-
语法
self.属性名
-
体验
# 1.定义洗衣机类 class Washer(): def print_info(self): # 类里面获取实例属性 print(f'haier洗衣机的宽度是{self.width}') print(f'haier洗衣机的高度是{self.height}') # 2.创建对象 haier = Washer() haier.width = 400 haier.height = 500 haier.print_info()
2.5魔法方法
在Python中,__
xx__
()的函数叫做魔法方法,指的是具有特殊功能的函数
2.5.1__init__()
2.5.1.1体验__init__()
__init__
方法的作用:初始化对象。
class Washer(): # 定义__init__,添加实例属性 def __init__(self): # 添加实例属性 self.width = 500 self.height = 800 self.color = 'red' def print_info(self): # 类里面调用实例属性 print(f'洗衣机的宽度是{self.width},高度是{self.height}') haier = Washer() # 洗衣机的宽度是500,高度是800 haier.print_info()
注意:
__init__()
方法,在创建一个对象时默认被调用,不需要手动调用
__init__(self)
中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递过去
2.5.1.2带参数的__init()
思考:一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢?
答:传参数
class Washer(): # 定义__init__,添加实例属性 def __init__(self, width, height, color): # 添加实例属性 self.width = width self.height = height self.color = color def print_info(self): # 类里面调用实例属性 print(f'洗衣机的宽度是{self.width},高度是{self.height},颜色是{self.color}') haier1 = Washer(100, 300, 'red') haier1.print_info() haier2 = Washer(400, 500, 'white') haier2.print_info()
2.5.2__str__()
当使用print输出对象的时候,默认打印对象的内存地址。如果定义了__str__
方法,那么就会打印从这个方法中return的数据
class Washer(): # 定义__init__,添加实例属性 def __init__(self, width, height, color): # 添加实例属性 self.width = width self.height = height self.color = color # 解释说明信息 def __str__(self): return '洗衣机宽度是:' + str(self.width) + ',洗衣机宽度:' + str(self.height) + ',洗衣机颜色是:' + self.color haier1 = Washer(100, 300, 'red') print(haier1)
2.5.3__del__()
当删除对象时,python解释器也会默认调用__del__()
方法
class Washer(): # 定义__init__,添加实例属性 def __init__(self, width, height, color): # 添加实例属性 self.width = width self.height = height self.color = color def __del__(self): print(f'{self}对象已经被删除') # <__main__.Washer object at 0x000002C8E3429080>对象已经被删除 haier1 = Washer(100, 300, 'red')
2.6综合应用
2.6.1烤地瓜
2.6.1.1需求:
需求:
-
被烤的时间和对应的地瓜状态:
0-3分钟:生的
3-5分钟:半生不熟
5-8分钟:熟的
超过8分钟:烤糊了
-
添加的调料
用户可以按自己的意愿添加调料
2.6.2步骤分析
需求涉及一个事物: 地瓜,故案例涉及一个类:地瓜类
2.6.2.1定义类
-
地瓜的属性
-
被烤的时间
-
地瓜的状态
-
添加的佐料
-
-
地瓜的方法
-
被烤
-
用户根据意愿设定每次烤地瓜的时间
-
判断地瓜被烤的总时间是在哪个区间,修改地瓜状态
-
-
添加佐料
-
用户根据意愿设定添加的佐料
-
将用户添加的佐料存储
-
-
-
显示对象信息
2.6.2.2代码实现
class SweetPotato(): def __init__(self): # 被烤的时间 self.cook_time = 0 # 烤的状态 self.cook_state = '生的' # 佐料列表 self.condiments = [] def cook(self, time): """烤地瓜方法""" self.cook_time += time if 0 <= self.cook_time < 3: self.cook_state = '生的' elif 3 <= self.cook_time < 5: self.cook_state = '半生不熟的' elif 5 <= self.cook_time < 8: self.cook_state = '熟了的' elif 8 <= self.cook_time: self.cook_state = '糊了的' def __str__(self): return f'这个地瓜烤了{self.cook_time}分钟,状态是{self.cook_state},添加的调料有{self.condiments}' def add_condiments(self, condiment): """添加佐料""" self.condiments.append(condiment) digua1 = SweetPotato() print(digua1) digua1.cook(2) digua1.add_condiments('辣椒面') print(digua1) digua1.cook(2) digua1.add_condiments('食盐') print(digua1) digua1.cook(2) digua1.add_condiments('孜然粉') print(digua1)
2.7继承
Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
# 父类A class A(object): def __init__(self): self.num = 1 def info_print(self): print(self.num) # 子类B class B(A): # 空语句,保持程序的完整性 pass result = B() result.info_print() # 1
在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫派生类
2.7.1单继承
所谓单继承就是一个类继承一个父类
# 1.师父类 class Master(object): def __init__(self): self.koufu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.koufu}制作煎饼果子') # 2.徒弟类继承师父类Master class Prentice(Master): pass # 3.创建对象daqiu daqiu = Prentice() # 4.对象访问实例属性 print(daqiu.koufu) daqiu.make_cake()
2.7.2多继承
所谓多继承就是一个类同时继承多个父类
# 1.师父类 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.学校类 class School(object): def __init(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.徒弟类 class Prentice(Master, School): pass # 3.创建对象daqiu daqiu = Prentice() # 4.对象访问实例属性 # [古法煎饼果子配方] print(daqiu.kongfu) # 运用[古法煎饼果子配方]制作煎饼果子 daqiu.make_cake()
注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法
2.7.3子类重写父类同名方法和属性
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(object): def __init(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Prentice(Master, School): def __init__(self): self.kongfu = '[独创煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') daqiu = Prentice() print(daqiu.kongfu) daqiu.make_cake() # 类名.__mro__得到该类的继承关系 print(Prentice.__mro__)
注意:当子类重写父类的同名属性和方法时,子类创建对象调用属性和方法时,调用到的是子类中的同名属性和方法
2.7.4子类调用父类的同名方法和属性
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(object): def __init__(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Prentice(Master, School): def __init__(self): self.kongfu = '[独创煎饼果子配方]' def make_cake(self): # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化 self.__init__() print(f'运用{self.kongfu}制作煎饼果子') def make_master_cake(self): # 如要调用父类的同名方法和属性,必须先调用__init()方法 Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) daqiu = Prentice() daqiu.make_cake() daqiu.make_master_cake() daqiu.make_school_cake() daqiu.make_cake()
2.7.5多层继承
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(object): def __init__(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Prentice(Master, School): def __init__(self): self.kongfu = '[独创煎饼果子配方]' def make_cake(self): # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化 self.__init__() print(f'运用{self.kongfu}制作煎饼果子') def make_master_cake(self): # 如要调用父类的同名方法和属性,必须先调用__init()方法 Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) class Tusun(Prentice): pass daqiu = Tusun() daqiu.make_cake() daqiu.make_master_cake() daqiu.make_school_cake()
2.7.6 super()调用父类方法
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(Master): def __init__(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.1super()带参数写法 # super(School, self).__init__() # super(School, self).make_cake() # 2.2super()不带参数写法 super().__init__() super().make_cake() class Prentice(School): def __init__(self): self.kongfu = '[独创煎饼果子配方]' def make_cake(self): # 如果是先调用了父类的属性和方法,父类属性会覆盖子类的属性,故在调用属性前,先调用自己子类的初始化 self.__init__() print(f'运用{self.kongfu}制作煎饼果子') # 需求:一次性调用父类School,Master的方法 def make_old_cake(self): # 方法一: 如果定义的类名修改,这里也要修改,麻烦,代码量大,冗余 # Master.__init__(self) # Master.make_cake(self) # School.__init__(self) # School.make_cake(self) # 方法二:super() # 方法2.1 super(当前类名,self).函数() # super(Prentice, self).__init__() # super(Prentice, self).make_cake() # 2.2super()不带参数写法 super().__init__() super().make_cake() daqiu = Prentice() daqiu.make_old_cake()
2.8私有权限
2.8.1定义私有属性和方法
在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。
设置私有权限的方法:在属性名和方法名前面加上两个下划线__
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(object): def __init__(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果子配方]' # 私有属性 self.__money = 2000 # 定义私有方法 def __info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Tusun(Prentice): pass # 对象不能访问私有属性和方法 # daqiu = Prentice() # print(daqiu.__money) # daqiu.info_print() # 子类无法继承父类的私有属性和私有方法 # xiaoqiu = Tusun() # print(xiaoqiu.__money) # xiaoqiu.__info_print()
2.8.2获取或修改私有属性值
在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值
class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class School(object): def __init__(self): self.kongfu = '[蜜汁煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果子配方]' self.__money = 2000 # 设置私有属性值 def set_money(self, money): self.__money = money # 获取私有属性值 def get_money(self): return self.__money # 定义私有方法 def __info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') class Tusun(Prentice): pass xiaoqiu = Tusun() xiaoqiu.set_money(200000000) print(xiaoqiu.get_money())
2.9面向对象三大特性
-
封装
-
将属性和方法书写到类的里面的操作即为封装
-
封装可以为属性和方法添加私有权限
-
-
继承
-
子类默认继承父类的所有属性和方法
-
子类可以重写父类的属性和方法
-
-
多态
-
传入不同的对象,产生不同的结果
-
2.9.1多态
多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)
-
定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
-
好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化
-
实现步骤:
-
定义父类,并提供公共方法
-
定义子类,并重写父类方法
-
传递子类对象给调用者,可以看到不同子类执行效果不同
-
2.9.2体验多态
class Dog(object): def work(self): # 父类提供统一方法,哪怕是空方法 pass class ArmyDog(Dog): # 继承Dog类 def work(self): # 子类重写父类同名方法 print("追击敌人...") class DrugDog(Dog): def work(self): print("追查毒品...") class Person(object): def work_with_dog(self, dog): # 传入不同的对象,执行不同的代码,即不同的work函数 dog.work() ad = ArmyDog() dd = DrugDog() person = Person() person.work_with_dog(ad) person.work_with_dog(dd)
2.9.3类属性和实例属性
2.9.3.1设置和访问类属性
-
类属性就是类对象所拥有的属性,它被该类的所有实例对象所共有
-
类属性可以使用类对象或实例对象访问
class Dog(object): tooth = 10 huahua = Dog() xiaohei = Dog() print(Dog.tooth) # 10 print(huahua.tooth) # 10 print(xiaohei.tooth) # 10
2.9.3.1.2修改类属性
类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建一个实例属性
class Dog(object): tooth = 10 huahua = Dog() xiaohei = Dog() # 修改类属性 Dog.tooth = 12 print(Dog.tooth) # 12 print(huahua.tooth) # 12 print(xiaohei.tooth) # 12 # 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性 huahua.tooth = 20 print(Dog.tooth) # 12 print(huahua.tooth) # 20 print(xiaohei.tooth) # 12
2.9.4类方法和静态方法
2.9.4.1类方法
2.9.4.1.1类方法特点
-
需要用装饰器
@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数
2.9.4.1.2类方法的使用场景
-
当方法中需要使用类对象(如访问私有属性等)时,定义类方法
-
类方法一般和类属性配合使用
class Dog(object): __tooth = 10 @classmethod def get_tooth(cls): return cls.__tooth wangcai = Dog() result = wangcai.get_tooth() print(result) # 10
2.9.4.2静态方法
2.9.4.2.1静态方法特点
-
需要通过装饰器
@staticmethod
来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls) -
静态方法也能够通过实例对象和类对象去访问
2.9.4.2.2静态方法使用场景
-
当方法中既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象(如类属性、类方法、创建实例等)时,定义静态方法
-
取消不需要的参数传递,有利于减少不必要的内存占用和性能消耗
class Dog(object): @staticmethod def info_print(): print("这是一个狗类,用于创建狗实例...") wangcai = Dog() # 静态方法既可以使用对象访问又可以使用类访问 wangcai.info_print() Dog.info_print()
3.异常
3.1了解异常
当检测到一个错误时,解释器无法继续执行时,反而出现了一些错误提示,这就是所谓的“异常”
例如:以r
方式打开一个不存在的文件
open('test.txt', 'r')
D:\software\Python\Python37\python.exe E:/PycharmProjects/Python_Base/Python_Test_1/面向对象.py Traceback (most recent call last): File "E:/PycharmProjects/Python_Base/Python_Test_1/面向对象.py", line 1, in <module> open('test.txt', 'r') FileNotFoundError: [Errno 2] No such file or directory: 'test.txt'
3.2异常的写法
3.2.1语法
try: 可能发生错误的代码 except: 如果出现异常执行的代码
3.2.2体验
需求:尝试以r
模式打开文件,如果文件不存在,则以w
方式打开
try: f = open('test.txt', 'r') except: f = open('test.txt', 'w') f.close()
3.3捕获指定异常
3.3.1语法
try: 可能发生错误的代码 except 异常代码: 如果捕获到该异常类型执行的代码
3.3.2体验
try: print(num) except NameError: print("有错误")
注意:
1.如果尝试执行的代码的异常类型和要捕获的异常类型不一致时,则无法捕获异常
2.一般try下只放一行尝试执行的代码
3.4捕获多个指定异常
当捕获多个指定异常时,可以把要捕获的异常类型的名字,放到except后,并使用元组的方式进行书写
try: print(1/0) except (NameError, ZeroDivisionError): print("有错误")
3.5捕获指定异常描述信息
try: print(1/0) except (NameError, ZeroDivisionError) as result: print(result)
3.6捕获所有异常
Exception是所有程序异常类的父类
try: print(num) except Exception as result: print(result)
3.7异常的else
else表示的是如果没有异常要执行的代码
try: print(1) except Exception as result: print(result) else: print("没有异常时,执行的代码")
3.8异常的finally
finally表示的是无论是否异常都要执行的代码,例如关闭文件
try: f = open('test1.txt', 'r') except: f = open('test1.txt', 'w') else: print("没有异常,真开心") finally: f.close()
3.9异常的传递
体验异常传递
需求:
-
尝试只读方式打开test.txt文件,如果文件存在则读取文件内容,文件不存在则提示用户即可
-
读取内容要求:尝试循环读取内容,读取过程中如果检测到用户意外终止程序,则
except
捕获异常并提示用户
import time try: f = open('test.txt') try: while True: content = f.readline() if len(content) == 0: break time.sleep(2) print(content) except: # 如果在读取文件的过程中,产生了异常,那么就会捕获到 # 比如按下了ctrl+c print("意外终止读取数据") finally: f.close() print("关闭文件") except: print("文件不存在")
3.10自定义异常
在Python中,抛出自定义异常的语法为raise 异常对象
需求:密码长度不足,则报异常(用户输入密码,如果输入的长度不足3位,则报错,即抛出自定义异常,并捕获该异常)
# 自定义异常类,继承Exception class ShortInputError(Exception): def __init__(self, length, min_len): self.length = length self.min_len = min_len # 设置抛出异常的描述信息 def __str__(self): return f'你输入的长度是{self.length},不能少于{self.min_len}个字符' def main(): try: con = input("请输入密码:") if len(con) < 3: raise ShortInputError(len(con), 3) except Exception as result: print(result) else: print("密码已经输入完成") main()
4.模块和包
4.1模块
Python模块(Module),是一个Python文件,以.py
结尾,包含了Python对象定义和Python语句
模块能定义函数,类和变量,模块里也能包含可执行的代码
4.1.1导入模块的方式
-
import 模块名
-
from 模块名 import 功能名
-
from 模块名 import *
-
import 模块名 as 别名
-
from 模块名 import 功能名 as 别名
4.1.1.1导入方式详解
1.import
-
语法
# 1.导入模块 import 模块名 import 模块名1,模块名2... # 不推荐 # 2.调用功能 模块名.功能名()
-
体验
import math print(math.sqrt(9))
2.from...import...
-
语法
# 1.导入模块 from 模块名 import 功能1, 功能2, 功能3... # 2.调用功能 功能名()
-
体验
from math import sqrt print(sqrt(9))
3.from...import *
-
语法
# 1.导入模块 from 模块名 import * # 2.调用功能 功能名()
-
体验
from math import * print(sqrt(9))
4.as定义别名
-
语法
# 模块定义别名 import 模块名 as 别名 # 功能定义别名 from 模块名 import 功能 as 别名
-
体验
# 模块别名 import time as tt tt.sleep(2) print("hello") # 功能别名 from time import sleep as sl sl(2) print('hello')
4.2制作模块
在Python中,每个Python中都可以作为一个模块,模块的名字就是文件的名字。也就是说自定义模块名必须要符合标识符命名规则
4.2.1定义模块
新建一个Python文件,命名为my_module1.py
,并定义testA
函数
def testA(a, b): print(a + b)
4.2.2测试模块
在实际开发中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如,在my_module1.py
文件中添加测试代码
def testA(a, b): print(a + b) # 测试信息 testA(1, 1)
此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行testA
函数的调用
解决办法如下:
def testA(a, b): print(a + b) # 只在当前文件调用该函数,其他导入的文件内不符合该条件,则不执行testA函数调用 # __name__是系统变量,是模块的标识符,值是:如果是自身模块,值是__main__,否则是当前模块的名字 if __name__ == '__main__': testA(1, 1)
4.2.3调用模块
import my_module1 my_module1.testA(2, 2)
4.3模块定位顺序
当导入一个模块,Python解析器对模块位置的搜索顺序是:
-
当前目录
-
如果不在当前目录,Python则搜索在shell变量PYTHONPATH的每个目录
-
如果都找不到,Python会查看默认目录。UNIX下,默认路径一般为/usr/local/lib/python/
模块搜素路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录
-
注意
-
自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
-
使用
from 模块名 import 功能
的时候,如果功能名字重复,调用到的是最后定义或导入的功能
-
4.4__all__
(all列表)
如果一个模块文件中有__all__
变量,当使用from xxx import *
导入时,只能导入这个列表中的元素
-
my_module1
模块的代码
__all__ = ['testA'] def testA(): print('testA') def testB(): print('testB')
-
导入模块的文件代码
from my_module1 import * testA() testB()
testA Traceback (most recent call last): File "E:/PycharmProjects/Python_Base/Python_Test_1/1.py", line 3, in <module> testB() NameError: name 'testB' is not defined
4.5包
包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py
文件,那么这个文件夹就称之为包
4.5.1制作包
[New]——[Python Package]——输入包名——[OK]——新建功能模块(有联系的模块)
注意:新建包后,包内部会自动创建__init__.py
文件,这个文件控制着包的导入行为
4.5.1.1快速体验
-
新建包
mypackage
-
新建包内模块:
my_module1和my_module2
-
模块代码如下
# my_module1 print(1) def info_print1(): print('my_module1')
# my_module2 print(2) def info_print1(): print('my_module2')
4.5.2导入包
4.5.2.1方法一
import 包名.模块名 包名.模块名.功能
4.5.2.2体验
import mypackage.my_module1 mypackage.my_module1.info_print1()
4.5.2.3方法二
注意:必须在__init__.py
文件中添加__all__ = []
,允许控制导入的模块列表
from 包名 import * 模块名.目标
4.5.2.4体验
from mypackage import * my_module1.info_print1()
__init__.py
代码
__all__ = ['my_module1']