-
在进行文件操作的时候,正确关闭一个文件非常重要,如果在文件读写后,没有正确关闭一个文件的话,则有可能导致文件损坏,文件内容丢失等问题。
我们使用文件对象的close()方法,来关闭一个文件。但是,使用close()方法,也不是100%安全的,如果在close()文件之前,程序异常退出了,那么文件也得不到正确的关闭。
在实际工程中,close()文件之前,为了正确关闭文件,需要考虑各种异常情况,这是非常麻烦的一件事,Python提供with关键字,可以免除这类后顾之忧。
with关键字对资源进行访问的场合,会确保不管在使用过程中是否发生异常,都会执行必要的“清理”的操作,释放资源,比如文件使用后自动关闭等等。with的使用方法如下:
with open('test.txt', 'r') as f: content = f.readlines() for line in content: print(line)
当文件使用结束后,不需要显式的调用f.close()关闭文件。
任务
假设test.txt文件有以下内容:
Hello World Hello Python Hello Imooc
请使用with语法,将文件的内容重复写一份追加到文件的尾部。
# coding=utf-8 with open('C:\\Users\\吕成鑫\\Desktop\\test.txt', 'a+') as f: f.seek(0) # 文件游标置首位 content = f.readlines() # 读取文件所有内容 f.seek(2) # 文件游标置尾部 f.writelines(content) # 追加写入文件尾部 # for line in content: # f.write(line)
查看全部 -
通过w的打开方式打开文件,会清空文件的内容,这在很多场景下是不合适的,比如写系统日志的时候,需要累积随时间推移的所有数据。
Python提供文件追加内容的打开模式,可以往文件尾部添加内容,又不清空文件原有的内容。
模式:
a 打开一个文件并追加内容,会往文件尾部添加内容
ab 以二进制格式打开一个文件并追加内容,会往文件尾部添加内容
a+ 打开一个文件并使用追加进行读写
使用a的打开方式打开文件,文件游标默认是在文件的尾部,因此,可以便捷的往文件尾部添加内容,除此以外,文件对象还提供seek()方法,可以移动文件的游标位置,它接受一个参数,表示文件的位置:
0:文件首部,
1:当前位置,
2:文件尾部
通过seek()可以把文件游标移动到文件首部但不删除文件的内容。
任务:
# 假设test.txt文件有以下内容:
Hello World Hello Python Hello Imooc
请将文件的内容重复写一份追加到文件的尾部。
# coding=utf-8 f1 = open('C:\\Users\\吕成鑫\\Desktop\\test.txt', 'a+') f1.seek(0) content = f1.readlines() f1.seek(2) f1.writelines(content) f1.close()
查看全部 -
要把字符串内容写入文件,需要使用w的模式打开文件。
模式:
w 打开一个文件进行写入,如果文件内容已存在,会清除原有的内容
wb 以二进制格式只写模式打开一个文件,会清除原有的内容
w+ 打开一个文件进行读写,如果文件内容已存在,会清除原有的内容
1. 写入若干字符
文件对象提供write(string)方法向文件内写入若干字符,它接受一个字符串参数,表示需要写入的字符串。
2. 写入若干行
文件对象提供writelines()方法向文件内容写入多行数据,它接受一个列表,表示需要写入的字符串列表。
任务:
# 有test.txt文件,包含以下内容:
Hello World Hello Python Hello Imooc
请从test.txt文件读取以上内容,并将每一行字符串反转,写入test1.txt文件。
dlroW olleH nohtyP olleH coomI olleH
f1 = open('C:\\Users\\吕成鑫\\Desktop\\test.txt', 'r') lines = f1.readlines() lines2 = [] f2 = open('C:\\Users\\吕成鑫\\Desktop\\test1.txt', 'w') for line in lines: line = ''.join(reversed(line[:-1])) line += '\n' lines2.append(line) f2.writelines(lines2) f1.close() f2.close()
注意:
1. 字符串反转可以使用切片实现: reverse = str_[::-1]
2. 换行符是'\n',字符串反转的时候,换行符也会翻转
查看全部 -
打开文件之后,就可以读取文件的内容,文件对象提供多种读取文件内容的方法。
1. 读取若干字符:
文件对象提供read()方法,可以读取文件中的若干个字符,它提供一个参数size,可以指定读取字符的数量。
test.txt内容:
Hello World. Hello Python. Hello Imooc.
s = f.read(5) print(s) # ==> Hello s = f.read(6) print(s) # ==> ' World'
当read()之后,访问文件的游标就会移动到第六个字符前面,此时,继续read,将得到Hello后面的结果。
2. 读取一行:
文件对象提供readline()方法,和read()方法类似,可以读取文件中的若干个字符,它也提供一个参数size,可以指定读取字符的数量,不过和read()方法不同的是,readline()方法遇到一行结束时就返回。
readline最多返回一行的所有字符。
3. 读取多行:
文件对象提供readlines()方法,可以读取多行字符,返回一个列表。它提供一个hint参数,表示指定读取的行数,没有指定则默认以列表的形式返回文件所有的字符串。
任务:
# 实现一个read.py文件,把read.py文件的内容打印出来。
# coding=utf-8 f = open('C:\\Users\\吕成鑫\\Desktop\\test2.py', 'r') content = f.readlines() print(content) f.close()
查看全部 -
除了文本以外,还有大量的非文本文件,比如图片、压缩文件、视频文件、音乐文件等等,这种文件统称为二进制文件,在Python中打开二进制文件,需要不同的打开模式。
模式:
b 二进制模式,打开二进制文件
wb 以二进制格式只写模式打开一个文件,会清除原有的内容
ab 以二进制格式打开一个文件并追加内容,会往文件尾部添加内容
rb 以二进制格式只读模式打开一个文件
任务:
# 请尝试用只读模式打开一个指定绝对路径的二进制文件,并正确关闭。
# coding=utf-8 f = open('C:\\Users\\吕成鑫\\Desktop\\1.png', 'rb') print(f.type()) f.close()
查看全部 -
通过print()可以从数据输出数据,通过input()可以向程序输入数据,但这些都是标准屏幕上的操作,本节课学习文件的读写操作。
open()函数可以打开一个文件,得到一个文件file对象,而file对象提供相关的方法对文件内容进行读写等操作。
open()函数有若干个参数,比较重要的是以下三个参数:
1. 文件路径:指定需要打开的文件的文件路径。
2. 打开模式:针对不同文件(二进制文件、文本文件)以及不同操作(读操作、写操作),会有不同的打开模式。
3. 编码:设定打开文件的默认编码。
常见模式:
t 文本模式(默认)。
x 写模式,新建一个文件。
b 二进制模式,打开二进制文件。
+ 更新一个文件(可读可写)。
r 以只读模式打开一个文件。
rb 以二进制格式只读模式打开一个文件。
w 打开一个文件进行写入,如果文件内容已存在,会清除原有的内容。
wb 以二进制格式只写模式打开一个文件,会清除原有的内容。
a 打开一个文件并追加内容,会往文件尾部添加内容。
ab 以二进制格式打开一个文件并追加内容,会往文件尾部添加内容。
w+ 打开一个文件进行读写,如果文件内容已存在,会清除原有的内容。
a+ 打开一个文件并使用追加进行读写。
注意:为了安全操作文件,文件使用完毕后,需要使用close()函数正确关闭。
注意:在打开文本文件是并不需要特别指定模式t,因为默认就是以文本方式打开文件的。
任务:
# 请尝试以只读模式打开一个指定绝对路径的文本文件,并正确关闭。
# coding=utf-8 f = open('C:\\Users\\吕成鑫\\Desktop\\L1.txt', 'r') print(type(f)) f.close()
当执行f.close()后,继续执行type(f)不报错,而继续执行print(f.read())就会报错:
查看全部 -
input()函数可以接收外部的输入。
注意:输入的是字符串,需要转型为数字类型。
num = input('please input number: ') num = int(num)
任务:
# eval()函数可以把字符串转换为等值的结果,比如eval('1+1'),得到结果为2。请使用eval实现一个简单的计算器,可以输入表达式并打印计算结果。
# coding=utf-8 while True: s = input('请输入表达式获取结果,输入break结束:') if s == 'break': break; res = eval(s) print(res)
查看全部 -
Python的官方模块已经提供了非常强大的能力。
大量热心开发者提供了非常好用的第三方库,在实际开发中,也会经常使用,比如Web开发框架:Django、Flask,异步任务框架:Celery等。
Python环境提供了安装第三方模块的工具:pip,通过这个工具,可以非常快捷的安装第三方模块。
安装Django模块:pip install django
卸载Django模块:pip uninstall django
任务:
# requests是一个好用的HTTP模块,请通过pip安装该模块
pip install requests
查看全部 -
导入官方模块的时候,不需要考虑路径问题,这是因为在搜索模块的时候,会默认包含官方模块的路径,所以导入官方模块不需要考虑路径的问题。
如果需要导入自定义模块,则需要了解Python导入模块搜索的路径。通过sys模块,可以知道导入模块的路径。
>>> import sys >>> sys.path ['', '/data/miniconda3/lib/python3.8', '/data/miniconda3/lib/python3.8/site-packages']
返回的是一个列表,表示的是在搜索Python模块时,会搜索的路径。
第一个路径是'',它是一个空字符串,表达的是当前路径的意思。
第二个路径是/data/miniconda3/lib/python3.8,它是Python默认模块的存放的路径,在这个路径下,可以发现有os、sys等模块的代码。
第三个路径是/data/miniconda3/lib/python3.8/site-packages,它是第三方模块代码的存放路径,在这个路径下,存放的是需要安装的第三方模块。
因为在搜索包的路径时,会搜索当前路径(上述:sys.path结果的第一项),因此在同一个目录内的tools.py模块,可以被搜索到,所以能够import进来。
任务:
# Python的sys.path返回的是一个路径列表,因此可以操作列表里面的元素,请通过sys.path增加路径'../',使得在运行时,可以导入当前目录上级目录的包。
# coding=utf-8 import sys lists = sys.path # 列表的引用 p = '../' # 需要追加进列表的路径 lists.append(p) # 追加操作 print(sys.path) # 打印列表结果
查看全部 -
要使用一个模块,我们必须首先导入该模块。Python使用import语句导入一个模块,Python官方提供很多有用的模块,比如:os模块、sys模块、time模块、math模块等等。
导入官方模块,不需要考虑路径的问题,直接导入即可。如果是导入自定义模块,则需要考虑路径问题。
导入官方模块math:import math
导入以后,你就可以认为math是一个指向已导入模块的变量,通过该变量,我们可以访问math模块中所定义的所有公开的函数、变量和类。
如果希望导入模块的指定部分属性或函数,那么使用from...import...语句。
如果希望导入模块里面的所有内容,那么使用from ...import *语句。
如果从一个模块导入函数,有可能会遇到导入的函数与本文件的函数冲突的情况。有两种方法可以解决这个问题,第一种是直接导入模块,不指定导入模块里面的具体内容;第二种方法就是使用from ... import as ...语句,as类似重命名,可以把导入的函数或属性重命名为别的名字。
任务:
# math模块还提供了非常多的数学计算函数,比如:正弦sin()函数,余弦cos()函数,请使用两种导入的方式,使用这两个函数。
# coding=utf-8 import math x = math.sin(60) # (不加math会报错) y = math.cos(60) print(x) print(y) # from math import sin,cos # x = sin(45) # (加了math会报错) # y = cos(60) # print(x) # print(y)
查看全部 -
要使用一个模块,我们必须首先导入该模块。Python使用import语句导入一个模块,Python官方提供很多有用的模块,比如:os模块、sys模块、time模块、math模块等等。
导入官方模块,不需要考虑路径的问题,直接导入即可。如果是导入自定义模块,则需要考虑路径问题。
导入官方模块math:import math
导入以后,你就可以认为math是一个指向已导入模块的变量,通过该变量,我们可以访问math模块中所定义的所有公开的函数、变量和类。
如果希望导入模块的指定部分属性或函数,那么使用from...import...语句。
如果希望导入模块里面的所有内容,那么使用from ...import *语句。
如果从一个模块导入函数,有可能会遇到导入的函数与本文件的函数冲突的情况。有两种方法可以解决这个问题,第一种是直接导入模块,不指定导入模块里面的具体内容;第二种方法就是使用from ... import as ...语句,as类似重命名,可以把导入的函数或属性重命名为别的名字。
任务:
# math模块还提供了非常多的数学计算函数,比如:正弦sin()函数,余弦cos()函数,请使用两种导入的方式,使用这两个函数。
# coding=utf-8
import math
x = math.sin(60) # (不加math会报错)
y = math.cos(60)
print(x)
print(y)
# from math import sin,cos
# x = sin(45) # (加了math会报错)
# y = cos(60)
# print(x)
# print(y)
查看全部 -
要使用一个模块,我们必须首先导入该模块。Python使用import语句导入一个模块,Python官方提供很多有用的模块,比如:os模块、sys模块、time模块、math模块等等。
导入官方模块,不需要考虑路径的问题,直接导入即可。如果是导入自定义模块,则需要考虑路径问题。
导入官方模块math:import math
导入以后,你就可以认为math是一个指向已导入模块的变量,通过该变量,我们可以访问math模块中所定义的所有公开的函数、变量和类。
如果希望导入模块的指定部分属性或函数,那么使用from...import...语句。
如果希望导入模块里面的所有内容,那么使用from ...import *语句。
如果从一个模块导入函数,有可能会遇到导入的函数与本文件的函数冲突的情况。有两种方法可以解决这个问题,第一种是直接导入模块,不指定导入模块里面的具体内容;第二种方法就是使用from ... import as ...语句,as类似重命名,可以把导入的函数或属性重命名为别的名字。
任务:
# math模块还提供了非常多的数学计算函数,比如:正弦sin()函数,余弦cos()函数,请使用两种导入的方式,使用这两个函数。
# coding=utf-8
import math
x = math.sin(60) # (不加math会报错)
y = math.cos(60)
print(x)
print(y)
# from math import sin,cos
# x = sin(45) # (加了math会报错)
# y = cos(60)
# print(x)
# print(y)
查看全部 -
Python语言本身提供了非常多的模块,比如数学模块math、cmath、decimal、statistics;文件模块pathlib、stat、shutil等;除了使用官方模块,有时候也需要自定义模块。
任务:
# 定义一个公共模块common.py,在common.py中,包含公共函数say_hello(name),它接受一个参数,输出:Hello 的结果。
# coding=utf-8 # common.py def say_hello(name): tamplate = 'Hello, {n}' res = tamplate.format(n = name) print(res) say_hello('绿花')
查看全部 -
Python模块和包:
模块的出现:
所有代码都写在一个py文件中,难以维护
把代码按功能划分到不同的文件
常见代码分类:
工具功能的代码:tools.py
公共函数的代码:common.py
第三方相关引入的代码:thirdparty.py
模块分类:
官方模块
自定义模块
第三方模块
包的出现:
模块多了,难以维护
把模块划分到不同的包
查看全部 -
Python中,函数其实是一个对象,我们可以将一个函数赋值给一个变量,而不改变函数的功能。
把内建函数abs()赋值给变量f之后,可以看到f就和abs一样,都是函数。
由于 f 可以被调用,所以,f 被称为可调用对象,而事实上,所有的函数都是可调用对象。
如果把一个类实例也变成一个可调用对象,可以用一个特殊的方法__call__()实现。
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __call__(self, friend): print('My name is {}...'.format(self.name)) print('My friend is {}...'.format(friend))
接着我们初始化一个Person对象,并对这个对象通过函数的方式调用:
>>> p = Person('Bob', 'Male') >>> p('Alice') # ==> 用函数的方式调用Person类的实例p My name is Bob... My friend is Alice...
任务:
# 请实现前面介绍过的斐波那契数列类Fib,加入__call__方法,使得调用的方式如下。
# coding=utf-8 class Fib(object): def __init__(self): self.fibs = [] def __call__(self, num): a = 0 b = 1 for i in range(num): self.fibs.append(a) a = b b = a + b return self.fibs f = Fib() print(f(10))
查看全部 -
由于Python是动态语言,任何实例在运行期都可以动态地添加属性。
如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的__slots__来实现。
使用__slots__ = ('name', 'gender', 'score') 限定Student类的属性,这个时候在外部再次添加动态属性age,将会报错。
__slots__的目的是限制当前类所能拥有的属性,避免因为外部属性的操作导致类属性越来越难以管理。
任务:
# 假设Person类通过__slots__定义了name和gender,请在派生类Student中通过__slots__继续添加score的定义,使Student类可以实现name、gender和score 3个属性。
# coding=utf-8 # 人类: class Person(object): __slots__ = ('name', 'gender') def __init__(self, name, gender): self.name = name self.gender = gender def __str__(self): return 'Person(name:{}, gender:{})'.format(self.name, self.gender) # 学生类: class Student(Person): # __slots__ = ('name', 'gender', 'score') __slots__ = ('score',) def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score def __str__(self): return 'Student(name:{}, gender:{}, score:{})'.format(self.name, self.gender, self.score) # 实例化: p1 = Person('莲华', '女') # p1.age = 22 # 报错:AttributeError: 'Person' object has no attribute 'age' # print(p1.age) print(p1) s1 = Student('万里', '男', 100) print(s1)
查看全部 -
Python很多的操作都是通过内建函数来实现的,比如最熟悉的加、减、乘、除,都是通过内建函数来实现的,分别是__add__、__sub__、__mul__、__truediv__。因此,只要我们的自定义类实现了相关的内建函数,我们的类对象,也可以做到加减乘除。
p、q 都是整数,表示有理数 p/q。
注意__add__()函数,它有一个参数,表示的是运算的第二个操作数,比如:r1 + r2,那么在__add__()方法中的参数,r指的就是r2,这个参数是运算符重载的时候传递的。
除法的特殊方法名字较长__truediv__,并且含有true这样的描述,这其实和Python除法是有关系的。
Python的除法可以分为地板除和普通除法,地板除的特殊方法是__floordiv__,普通除法是__truediv__。地板除法的结果只会向下取整数。普通除法使用/表示,而地板除使用//表示。任务:
# Rational类虽然可以做加法,但无法做减法、乘法和除法,请继续完善Rational类,实现四则运算。
# coding=utf-8 # 有理递归数化简: def gcb(a, b): if b == 0: return a return gcb(b, a % b) # 有理数p/q class Rational(object): def __init__(self, p, q): self.p = p self.q = q # 有理数加法: def __add__(self, r): return Rational(self.p * r.q + self.q * r.p, self.q * r.q) # 有理数减法: def __sub__(self, r): return Rational(self.p * r.q - r.p * self.q, self.q * r.q) # 有理数乘法: def __mul__(self, r): return Rational(self.p * r.p, self.q * r.q) # 有理数除法:(除以一个数,等于乘它的倒数) # def __truediv__(self, r): def __div__(self, r): return Rational(self.p * r.q, self.q * r.p) # 有理数格式化输出: def __str__(self): g = gcb(self.p, self.q) return '{}/{}'.format(int(self.p/g), int(self.q/g)) r1 = Rational(1, 2) r2 = Rational(1, 5) print(r1 + r2) print(r1 - r2) print(r1 * r2) print(r1 / r2)
查看全部 -
对于列表List或者元组Tuple,通过内建方法len(),可以得出列表或者元组中元素的个数。如果一个类表现得像一个list,想使用len()函数来获取元素个数时,则需要实现__len__()方法。
通过自定义__len__()方法,可以让len()函数返回相关的结果,如果没有定义__len__()方法的类使用len()函数获取长度时,将会引起异常。
任务:
# 斐波那契数列是由 0, 1, 1, 2, 3, 5, 8...构成。
请编写一个Fib类,Fib(10)表示数列的前10个元素,print Fib(10) 可以打印出数列的前 10 个元素,len(Fib(10))可以正确返回数列的个数10。
# coding=utf-8 class Fib(object): def __init__(self, num): self.num = num self.fibs = [] a = 0 b = 1 for i in range(num): self.fibs.append(a) a, b = b, a + b # 此句等同于: # a = b # b = a+b def __str__(self): return str(self.fibs) def __len__(self): return self.num fibs = Fib(10) print(fibs) num = len(fibs) print(num)
查看全部
举报