Python语法--面向对象
此片整理了Python的面向对象的一些基础概念,基础语法
面向对象
面向对象三大特性:封装,继承和多态
- 封装 根据职责将属性和方法封装到一个抽象的类中
- 继承 实现代码的重用,相同的代码不需要重复的编写
- 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
类和对象
类和对象是面向对象编程的两个核心概念
类
类是对一群具有相同特征或者行为的事物的统称,是抽象的,不能直接使用.类就相当于制造飞机时的图纸,是一个模板
- 特征被称为属性
- 行为被称为方法
对象
对象是有类创建出来的一个具体存在,可以直接使用.由那一个类创建出来的对象,就拥有在那个类中定义的属性和方法.对象就相当于用图纸制造出来的飞机.在程序开发中,应该先有类,再有对象
封装
内置函数 dir
查看对象内所有属性及方法:
- 在标识符/数据后输入一个.PyCharm中会提示该对象能够调用的方法列表
- 使用内置函数dir()传入标识符/数据,可以查看对象内的所有属性及方法
提示:
__方法名__格式的方法是python提供的内置方法/属性
方法名 | 类型 | 作用 |
---|---|---|
__new__ | 方法 | 创建对象时,会被自动调用 |
__init__ | 方法 | 对象被初始化时,会被自动调用 |
__del__ | 方法 | 对象被从内存中销毁前,会被自动调用 |
__str__ | 方法 | 返回对象的描述信息,print()函数输出使用 |
类的定义
定义简单的类(只包含方法):
面向对象是更大的封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了.
语法格式:
class 类名:
def 方法1(self,参数列表):
pass
def 方法2(self,参数列表):
pass
"""
类方法的定义格式和上一篇帖子中的函数差不多一样,
不同处在于第一个参数必须是self,后面会介绍一下self
"""
# 创建对象
对象变量名 = 类名()
# 举例:
class Cat:
"""
这是一个Cat类
"""
def eat(self):
print("小猫爱吃鱼~")
def drink(self):
print("小猫在喝水,吨吨吨~~")
tom = Cat()
print(tom)
tom.eat()
tom.drink()
"""
<__main__.Cat object at 0x00000212E6826BB0>
小猫爱吃鱼~
小猫在喝水,吨吨吨~~
"""
引用概念的强调:
在面向对象开发中,引用的概念是同样适用的
- 在Python中使用类创建对象之后,tom变量中仍然记录的是对象的内存中的地址
- 也就是tom变量引用了新建的Cat对象
- 使用print()函数输出对象变量,默认情况下,是能够输出这个变量引用对象是由哪一个类创建的对象,以及内存地址(十六进制表示,计算中通常使用十六进制表示内存地址)
self参数
self参数代表当前对象实例本身,所以在各种自定义的类方法中,self能发挥作用.但有趣的是self在Python中并不是关键字,我们甚至可以使用其他名称代替这个在类方法中必须第一个定义的参数,但是使用self已经成为了Python程序员一个约定俗成的事情,建议大家遵循这个约定.
- 在类方法中,self就表示当前调用方法的对象自己
- 调用方法时,程序员不需要传递参数self
- 在类方法内部可以通过self.访问对象的属性
- 也可以通过self.调用其他的对象方法
初始化方法
当使用类名()创建对象时,会自动执行以下操作
- 为对象在内存中分配空间-----创建对象
- 为对象的属性设置初始值-----执行初始化方法__init__
定义属性:
__init__方法是专门用来定义一个类具有那些属性的方法
语法格式:
# 在__init__方法内部使用self.属性名 = 属性的初始值
class Cat:
"""
这是一个Cat类
"""
def __init__(self):
print("这是一个初始化方法")
# 定义一个属性值
self.name = "tom"
def eat(self):
print("%s爱吃鱼~" % self.name)
def drink(self):
print("%s在喝水,吨吨吨~~" % self.name)
tom = Cat()
tom.eat()
tom.drink()
"""
这是一个初始化方法
<__main__.Cat object at 0x000001723DA40A90>
tom爱吃鱼~
tom在喝水,吨吨吨~~
"""
__init__方法改造:
在开发中,如果希望在创建对象的同时,设置对象的属性,可以对__init__方法进行改造
- 把希望设置的属性值,定义成__init__方法的参数
- 在方法内部使用self.属性名 = 形参接收外部传递的参数
- 在创建对象时使用类名(属性1,属性2…)调用
class Cat:
"""
这是一个Cat类
"""
def __init__(self, name):
print("这是一个初始化方法")
# 定义一个属性值
self.name = name
def eat(self):
print("%s爱吃鱼~" % self.name)
def drink(self):
print("%s在喝水,吨吨吨~~" % self.name)
tom = Cat("tom")
tom.eat()
tom.drink()
"""
这是一个初始化方法
tom爱吃鱼~
tom在喝水,吨吨吨~~
"""
注意:
这个时候对象变量名 = 类名(属性1,属性2…)中的属性是必传值,否则程序会报错
内置方法
方法名 | 类型 | 作用 |
---|---|---|
__del__ | 方法 | 对象被从内存中销毁前,会被自动调用 |
__str__ | 方法 | 返回对象的描述信息,print函数输出使用 |
__del__方法:
如果希望在对象被销毁前,再做一些事情,可以放在__del__中
__str__方法:
在Python中,使用print()输出对象变量,默认情况下,会输出这个变量引用对象是由哪一个类的对象,以及内存中的地址.如果在开发中,希望使用print()输出对象变量时,能够打印自定义内容,就可以使用__str__方法
class Cat:
"""
这是一个Cat类
"""
def __init__(self, name):
# print("这是一个初始化方法")
# 定义一个属性值
self.name = name
def eat(self):
print("%s爱吃鱼~" % self.name)
def drink(self):
print("%s在喝水,吨吨吨~~" % self.name)
def __str__(self):
return "我是一只小猫%s" % self.name
tom = Cat("tom")
print(tom)
"""
我是一只小猫tom
"""
私有属性和私有方法
应用场景:
在实际开发中,对象中的某些属性或者方法,可能只希望在对象的内部被使用,而不希望在外部被访问到.私有属性就算对象不希望公开的属性,私有方法就是对象不希望公开的方法
语法格式:
# 在定义属性或者方法时,在属性名或者方法名前增加两个下划线,定义的就算私有属性或者私有方法
class Woman:
def __init__(self, name):
self.name = name
self.__age = 18
def secret(self):
print("%s的年纪是%s" % (self.name, self.__age))
xiaofang = Woman("张三")
print(xiaofang.name)
# print(xiaofang.__age) 程序会报错
xiaofang.secret() # 这时候是可以访问到xiaofang的年纪的
注意:
在日常开发中不要使用以下方式访问对象的私有属性或者私有方法
在对象变量后面加上._类名__私有属性名/私有方法名
class Woman:
def __init__(self, name):
self.name = name
self.__age = 18 # 私有属性
def __secret(self): # 私有方法
print("%s的年纪是%s" % (self.name, self.__age))
xiaofang = Woman("张三")
print(xiaofang._Woman__age)
xiaofang._Woman__secret()
"""
18
张三的年纪是18
"""
# 这样是可以访问到的,但不建议这样做
父类的私有属性和私有方法:
- 子类对象不能在自己的方法内部直接访问父类的私有属性或者私有方法
- 子类对象通过父类的共有方法间接的访问私有属性或者私有方法(效果和Java中的getter/setter方法差不多)
继承
继承的概念:子类拥有父类的所有方法和属性
单继承
语法格式:
class 类名(父类名):
pass
# 举例:
class Animal:
def eat(self):
print("Animal吃东西")
from Animal import Animal
class Dog(Animal):
def bark(self):
print("小狗会叫,汪汪汪~~~")
xiaoHei = Dog()
xiaoHei.eat()
"""
Animal吃东西
"""
"""
注意:
Python中import是导入的模块,模块和类名是两个不同的空间
上面的代码如果是import Animal,在继承Animal时应该是
class Dog(Animal.Animal): # 前面的Animal是模块名,后面的才是类名
pass
"""
- 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
- 子类中应该根据职责,封装子类特有的属性和方法
- 子类拥有父类以及父类的父类中封装的所有方法和属性
重写
应用场景:
当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)
重写父类方法的两种情况:
- 覆盖父类的方法
- 对父类方法进行扩展
覆盖父类的方法
如果在开发中,父类的方法实现和子类的方法实现完全不同,就可以使用覆盖的方式,在子类中重写编写父类的方法实现.
具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类中封装的方法.
对父类方法进行扩展
如果在开发中子类的方法实现中包含父类的方法实现,即父类原本封装的方法实现是子类方法的一部分,这时就可以使用扩展的方式
具体实现方式如下:
- 在子类中重写父类的方法
- 在需要的位置使用super().父类方法来调用父类方法来执行
- 代码其他位置针对子类的需求,编写子类特有的代码实现
关于super
- 在Python中super是一个特殊的类
- super()就是使用super类创建出来的对象
- 最常见的使用场景就是在重写父类方法时,调用在父类中封装的方法实现
在Python2.x时,使用的时父类名.方法(self)的方式调用父类中的方法,这中方式在Python3.x中还是支持的,但这种方法不推荐使用,因为一旦父类发生变化,方法调用位置的类名就需要修改
注意:
在开发时,父类名和super()两种方式不要混用,如果使用当前子类名调用方法,会形成递归调用,出现死循环
多继承
子类可以拥有多个父类,并且具有所有父类的属性和方法
语法格式:
class 子类名(父类名1,父类名2...):
pass
使用多继承的注意事项:
在开发时,应该尽量避免不同的父类中存在同名的方法的情况,如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承
Python中的MRO(方法搜索顺序):
Python中针对类提供了一个内置属性__mro__可以查看方法的搜索顺序,MRO是methon reslution order的缩写,主要用于在多继承时判断方法,属性的调用顺序
# 语法格式:
# 类名.__mro__
from Animal import Animal
from Animal import Alive
class Dog(Animal, Alive):
def bark(self):
print("小狗会叫,汪汪汪~~~")
xiaoHei = Dog()
xiaoHei.eat()
xiaoHei.alive()
print(Dog.__mro__)
"""
Animal吃东西
活的
(<class '__main__.Dog'>, <class 'Animal.Animal'>, <class 'Animal.Alive'>, <class 'object'>)
"""
- 在搜索方法时,是按照__mro__的输出结果从左到右的顺序查找的
- 如果在当前类中找到方法,就直接执行,不在搜索
- 如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
- 如果找到最后一个类,还没有找到,程序报错
新式类与旧式(经典类)
object是Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看
- 新式类: 以object为基类,推荐使用
- 经典类: 不以object为基类,不推荐使用
- 新式类和经典类再多继承时,会影响到方法的搜索顺序
- 在Python3.x中定义类时,如果没有指定父类,会默认使用object作为该类的基类–Python3.x中定义的类都是新式类
- 在Python2.x中定义类时,如果没有指定父类,则不会以object作为基类
tips:
为了保证,编写代码能够同时在2.x和3.x下运行,今后定义类时,如果没有父类,同一继承自object
class 类名(object):
pass
多态
面向对象三大特性:
- 封装根据职责将属性和方法封装到一个抽象的类中
- 定义类的准则
- 继承实现代码的重用,相同的代码不需要重复的编写
- 设计类的技巧
- 子类针对自己特有的需求,编写特定的代码
- 多态不同的子类对象调用相同的父类方法,产生不同的执行结果
- 多态可以增加代码的灵活度
- 以继承和重写父类方法为前提
- 是调用方法的技巧,不会影响到类的内部设计
类
实例
- 使用面向对象开发,第1步是设计类
- 使用类名()创建对象,创建对象的两步动作
- 在内存中为对象分配空间 (__new__方法分配)
- 调用初始化方法__init__为对象初始化
- 对象创建后,内存中就有了一个对象的实实在在的存在----实例
- 创建出来的对象叫做类的实例
- 创建对象的动作叫做实例化
- 对象的属性叫做实例属性
- 对象的方法叫做实例方法
总结:
- 每个对象都有自己的独立的内存空间,保存各自不同的属性
- 多个对象的方法,在内存中只有一份,在调用时,需要把对象的引用传递到方法内部
类是一个特殊的对象
Python中一切皆对象:
class AAA:定义的类属于类对象
obj = AAA()属于实例对象
- 在程序运行时,类同样会被加载到内存中
- 在Python中,类是一个特殊的对象—类对象
- 在程序运行时,类对象在内存中只有一份,使用一个类可以创建出很多个对象实例
- 除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法,称为类属性,类方法
- 通过**类名.**的方式可以调用
类属性和实例属性
- 类属性就是在类对象中定义的属性
- 通常用来记录与这个类相关的特征
- 类属性不会用于记录具体对象的特征
class Tool(object):
# 使用赋值语句,定义类属性,记录创建工具对象的总数
count = 0
def __init__(self, name):
self.name = name
# 争对类属性做一个计数
Tool.count += 1
# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("锤子")
tool3 = Tool("铁锹")
print(Tool.count)
"""
3
"""
属性的获取机制:
在Python中属性的获取存在一个向上查找机制
访问类属性有两种方式:
- 类名.类属性
- 对象.类属性(不推荐)
注意:
如果使用对象.类属性 = 值赋值语句,只会给对象添加一个属性,而不会影响到类属性的值
类方法和静态方法
类属性
- 类属性就是针对类对象定义的属性
- 使用赋值语句在class关键字下方定义类属性
- 类属性用于记录与这个类相关的特征
类方法
- 类方法就是针对类对象定义的方法
- 在类方法内部可以直接访问类属性或者调用其他的类方法
语法格式:
@classmethod
def 类方法名(cls):
pass
-
类方法需要用修饰器**@classmethod**来标识,告诉解释器这是一个类方法
-
类方法的第一个参数应该是cls
- 由哪一个类调用的方法,方法内的cls就是哪一个类的引用
- 这个参数和实例方法的第一个参数是self类似
- 提示使用其他名称也可以,不过习惯使用cls
-
通过类名.调用类方法,调用方法时,不需要传递cls参数
-
在类方法内部可以通过cls.访问类的属性或者调用其他的类方法
静态方法
在开发时,如果需要在类中封装一个方法,这个方法既不需要访问实例属性,或者调用实例方法,也不需要调用类属性或者类方法.这个时候我们可以把这个方法封装成一个静态方法
语法格式:
@staticmethod
def 静态方法名():
pass
# 通过类名.调用静态方法
__new__
使用类名()创建对象时,Python的解释器首先会调用__new__方法为对象分配空间,__new__是一个由object基类提供的内置的静态方法,主要作用如下:
- 在内存中为对象分配空间
- 返回对象的引用
Python的解释器获得对象的引用后,将引用作为第一个参数,传递个__inint__方法,重写__new__方法的代码非常固定!
- 重写__new__方法一定要return.super().new(cls)
- 否则Python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
- __new__是一个静态方法,在调用时需要主动传递cls参数
单例
让类创建的对象在系统中只有一个唯一的实例对象,步骤如下:
- 定义一个类,初始值是None,用于记录单例对象的引用
- 重写__new__方法
- 如果类属性is None,调用父类方法分配空间,并在类属性中记录结果
- 返回类属性中记录的对象引用
代码示例:
class MusicPlayer(object):
# 记录第一个被创建对象的引用
instance = None
def __new__(cls, *args, **kwargs):
# 1,判断类属性是否是空对象
if cls.instance is None:
# 2,调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 3,返回类属性保存的对象引用
return cls.instance
# 创建多个对象
p1 = MusicPlayer()
print(p1)
p2 = MusicPlayer()
print(p2)
"""
<__main__.MusicPlayer object at 0x000001D9A272DF40>
<__main__.MusicPlayer object at 0x000001D9A272DF40>
"""
只执行一次初始化优化:
上面的单例会存在一个__init__方法执行多次的问题,在每次使用类名()创建对象时,Python解释器都会自动的执行__new__和__init__两个方法,这里将初始化动作只会被执行一次
优化如下:
class MusicPlayer(object):
# 记录第一个被创建对象的引用
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
# 1,判断类属性是否是空对象
if cls.instance is None:
# 2,调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 3,返回类属性保存的对象引用
return cls.instance
def __init__(self):
# 1,判断是否执行过初始化动作
if MusicPlayer.init_flag:
return
# 2,如果没有执行过,就执行初始化动作
print("初始化播发器")
# 3,修改类属性的标记
MusicPlayer.init_flag = True
# 创建多个对象
p1 = MusicPlayer()
print(p1)
p2 = MusicPlayer()
print(p2)
"""
初始化播发器
<__main__.MusicPlayer object at 0x0000021FCB2BDF40>
<__main__.MusicPlayer object at 0x0000021FCB2BDF40>
"""
异常
异常的概念
- 程序运行时,如果Python解释器遇到一个错误,会停止程序的执行,并且提示一些错误信息,这就是异常
- 程序停止执行并且提示错误信息这个动作,我们称之为抛出(raise)异常
程序开发时,很难将所有的特殊情况都处理的面面俱到,通过异常捕获可以针对突发事件做集中处理,从而保证程序的稳定性和健壮性
捕获异常
简单捕获异常语法格式:
try:
尝试执行的代码
except:
出现错误时执行的代码
"""
try 尝试,下方编写要尝试的代码,不确定是否能够正常执行的代码
except 如果不是,下方编写尝试失败后的代码
"""
错误类型捕获语法格式:
在程序执行时,可能会遇到不同类型的异常,并且需要针对不同类型的异常,做出不同的响应
当Python解释器抛出异常后,最后一行错误信息的第一个单词,就是错误类型
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except (错误类型2,错误类型3):
# 针对错误类型2和3,对应的代码处理
pass
except Exception as result:
# 捕获未知错误
print("未知错误 %s" % result)
异常捕获的完整语法格式:
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except 错误类型2:
# 针对错误类型2,对应的代码处理
pass
except (错误类型3,错误类型4):
# 针对错误类型3和4,对应的代码处理
pass
except Exception as result:
# 捕获未知错误
print("未知错误 %s" % result)
else:
# 没有异常才会执行的代码
pass
finally:
# 无论是否有异常,都会执行的代码
print("无论是否有异常,都会执行的代码")
说明:
else只有在没有异常时才会执行的代码
finally无论是否有异常,都会执行的代码
异常的传递
当函数/方法执行出现异常,会将异常传递给函数/方法调用一方,如果传递到主程序,仍让没有异常处理,程序才会被终止
- 在开发中,可以在主函数中增加异常捕获
- 而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的异常捕获中
- 这样就不需要再代码中,增加大量的异常捕获,能够保证代码的整洁
抛出raise异常
在开发中,除了代码执行出错Python解释器会抛出异常之外,还可以根据程序特有的业务需求主动抛出的异常.例如,密码长度验证的需求
Python中提供了一个Exception异常类,在开发时,如果满足特定业务需求时,希望抛出异常
- 创建一个Exception的对象
- 使用raise关键字抛出异常对象
def input_password():
password = input("请输入密码")
# 密码长度>=8返回密码,否则抛出异常
if len(password) >= 8:
return password
# 定义自定义异常对象
ex = Exception("请确保密码长度大于等于8")
raise ex
try:
pwd = input_password()
print(pwd)
except Exception as result:
print(result)
"""
请输入密码1
请确保密码长度大于等于8
"""
模块
模块是Python程序架构的一个核心概念
- 每个以扩展名.py结尾的Python源代码文件都是一个模块
- 模块名同样也是一个标识符,需要符合标识符的命名规则
- 在模块中定义的全局变量,函数,类都是提供给外界使用的工具
- 模块好比一个工具包,要想使用这个工具包中的工具,就需要先导入这个模块
模块的两种导入方式
import导入
语法格式:
# 在导入模块时,每个导入应该独占一行
import 模块名1
import 模块名2
import 这是一个名称很长的模块名 as 模块别名
说明:
- 通过模块名.使用模块提供的工具,全局变量,函数,类等
- 如果模块名称太长,可以使用as指定模块的别名,以便在代码中使用
- 模块别名应该符合大驼峰命名法
form … import
如果希望从某一个模块中,导入部分工具,就可以使用form … import的方式
import 模块名是一次性把模块中所有工具全部导入,并且通过模块名/别名访问
语法格式:
# 从模块导入某一个工具
form 模块名1 import 工具名
# 从模块中导入所有工具
# 不推荐使用这种方式,因为函数重名没有任何提示,出现问题不好排查
form 模块名 import *
说明:
- 不需要通过模块名.的方式调用,可以直接使用模块提供的工具(全局变量,函数,类)
- 如果两个模块,存在同名的函数,那么后导入模块的函数,会覆盖掉先导入的函数
- 开发时,import代码应该同一写在代码的顶部,更容易及时的发现冲突
- 一旦冲突,可以使用as关键字给其中一个工具起一个别名
模块的搜索顺序
- 搜索当前目录指定模块名的文件,如果有就直接导入
- 如果没有,再搜索系统目录
- 在开发时,给文件起名,不要和系统的模块文件名重名
- Python中每个模块都有一个内置属性__file__可以查看模块的完整路径
原则
一个独立的Python文件就是一个模块,在导入文件时,文件中没有任何缩进的代码都会被执行一遍
那么在实际开发中,开发人员通常会在模块下方增加一些测试代码,仅在模块内部使用,被导入到其他文件中不需要执行,这时候就会用到__name__属性
__name__属性
- __name__属性可以作到,测试模块的代码只在测试情况下运行,而在被导入时不会被执行
- __name__是Python的一个内置属性,记录着一个字符串
- 如果是被其他文件导入的,__name__就是模块名
- 如果是当前执行的程序,__name__是__main__
所有在很多Python中都会看到以下格式的代码:
# 导入模块
# 定义全局变量
# 定义类
# 定义函数
# 在代码的最下方
def main():
pass
# 根据__name__判断是否执行下方代码
if __name__ == "__main__":
main()
包
- 包是一个包含多个模块的特殊目录
- 目录下有一个特殊文件__init__.py
- 报名的命名方式小写字母+_
要在外界使用包中的模块,需要在__init__.py中指定对外界提供的模块列表
语法格式:
# 在__init__.py中指定该包下能对外提供的模块列表
from . import 模块名1
from . import 模块名2
发布模块
将自己开发的模块,分享给其他人使用,就可以用到发布模块
以下内容是基于win10
制作发布压缩包步骤
(1)创建setup.py
setup.py文件内容如下:
# coding:utf-8
from distutils.core import setup
setup(name="test", # 项目名
version="1.0",
description="测试发布压缩包步骤",
long_description="第一次测试发布压缩包步骤",
author="kiwi",
author_email="761791958@qq.com",
url="www.*****.com",
py_modules=["chap3.dog", "chap3.Animal"]) # 你自己的模块名,可多个
有关setup.py中的参数的详细信息,可以参阅官方网站:
(2)生成模块
# 打开setup.py所在的路径,地址栏输入cmd黑窗口中执行
python.exe setup.py sdist
安装模块
将上一步生成的tar.gz文件拷贝到你需要用到该模块的路径下解压,然后执行命令
python.exe setup.py install
文件
操作文件的函数/方法
在Python中要操作文件需要记住1个函数3个方法
名称 | 类型 | 说明 |
---|---|---|
open | 函数 | 打开文件(文件名区分大小写),并且返回文件操作对象 |
read | 方法 | 将文件内容读取到内存 |
write | 方法 | 将指定内容写入到文件 |
close | 方法 | 关闭文件 |
打开文件的方式
open函数默认是以只读方式打开文件,并且返回文件对象
语法格式:
f = open("文件名", "访问方式")
访问方式 | 说明 |
---|---|
r | 以只读的方式打开文件,文件的指针将会房子文件的开头,这是默认模式,如果文件不存在就会抛出异常 |
w | 以只写方式打开文件,如果文件存在会被覆盖,如果文件不存在则创建新文件 |
a | 以追加方式打开文件,如果该文件已经存在,文件指针会放在文件的末尾,如果文件不存在,会创建新文件进行写入 |
r+ | 以读写方式打开文件,文件的指针将会放在,文件的开头,如果文件不存在,抛出异常 |
w+ | 以读写方式打开文件,如果文件存在会被覆盖,如果不存在则创建新文件 |
a+ | 以读写方式打开文件,如果该文件已经存在,文件指针将会放在文件的结尾,如果文件不存在,创建新文件进行写入 |
提示:
- 如果忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问,所有操作文件的最后一步都需要close一下
- 方法执行后,会把文件的指针移动到文件的末尾
- 频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候只会以只读或者只写的方式来操作文件
按行读取文件内容
read方法默认会把文件的所有内容一次性读取到内存,如果文件太大,对内存的占用会非常严重,这时候我们可以使用readLine方法
readLine方法
readLine方法可以一次读取一行内容,方法执行后,会把文件指针移动到下一行,准备再次读取
读取大文件:
file = open("README")
while True:
text = file.readline()
if not text:
break
print(text, end="")
file.close()
小文件复制:
# 打开文件
file_read = open("README")
file_write = open("README(复件)", "w")
# 读取并写入文件
text = file_read.read()
file_write.write(text)
# 关闭资源
file_read.close()
file_write.close()
大文件复制:
# 打开文件
file_read = open("README")
file_write = open("README(复件)", "w")
# 读取并写入文件
while True:
text = file_read.readline()
if not text:
break
file_write.write(text)
# 关闭资源
file_read.close()
file_write.close()
文件/目录的常用操作
在终端/文件浏览器中可以执行常规的文件/目录操作,例如:创建,重命名,删除,改变路径,查看目录内容等
在Python中实现上述功能需要导入os模块
文件操作:
方法名 | 说明 | 示例 |
---|---|---|
rename() | 重命名文件 | os.rename(源文件名,目标文件名) |
remove() | 删除文件 | os.remove(文件名) |
目录操作:
方法名 | 说明 | 示例 |
---|---|---|
listdir() | 目录列表 | os.listdir(目录名) |
mkdir() | 创建目录 | os.mkdir(目录名) |
rmdir() | 删除目录 | os,rmdir(目录名) |
getcwd() | 获取当前目录 | os.getcwd() |
chdir | 修改工作目录 | os.chdir(目标目录) |
path.isdir() | 判断是否是文件 | os.path.isdir(文件路径) |
提示:
文件或者目录操作都支持相对路径和绝对路径
至此,2022年新年在家学习的Python继承部分笔记全部整理完毕