Self-study Python Fish-C Note15 P54to56

永久储存

本节主要讲解 永久储存 (python文件写入的内容)
当我们程序运行起来的时候,大多数数据都是从硬盘转移到了内存中,因为内存和我们CPU之间的数据传输速度比硬盘和CPU之间快很多。但是内存不能断电,一旦断电或者系统重启,那么里面的数据就会被抹去。当我们使用 Ctrl+S 保存后,数据会被保存到硬盘里。

操作文件 (P54)

文件:计算机系统中由操作系统管理的具有名称的存储区域

open() 函数

open() 函数 用于打开一个文件
示例,f = open('example.txt','w')
第一个参数 file 参数这里赋值 'example.txt',用来指定文件路径和文件名,如果没有添加路径的话就默认在Python的主文件夹下面。这里我们会在这个 .ipynb 文件所在的目录下创建了一个 example.txt 文件(example.txt 原本不存在)。
第二个参数 mode 这里是 'w' 代表打开一个文件只用于写入。如果该文件不存在,则创建新文件。但如果该文件已存在则打开文件,删除原有内容, 并从开头开始编辑。
注意:不要轻易用 'w' 打开一个已经存在的文件,只要 f=open('xxx.txt','w') 打开已经存在的 xxx.txtxxx.txt 里的内容就被删除(即如果立马 f.close() 的话得到一个空白的 xxx.txt)。
这里 open 函数打开文件后会返回一个文件对象,这里我们将这个文件对象给变量 f 里去。
这里只是举一个简单的例子,open函数还有很多其他参数可以看这个文档 https://www.runoob.com/python/python-func-open.html

f = open('example.txt','w')

创造出的文件对象有很多方法,比如 f.writef.writelines(这两种方法可以将字符串写入到文件对象中)。其他很多方法可以上网搜各路大神总结的文件对象方法大合集,这里我常用:https://www.cainiaoplus.com/python/python-methods-file.html

f.write('This is abc.') # 返回写入的字符个数
12
# 使用 writelines 方法可以同时将多个字符串写入到文件对象里去
f.writelines(['aaa\n','bbb\n','ccc','ddd','eee'])  # 注意 writelines 不会自动给添加换行符,如果我们需要换行要自己添加
# 运行完后 writelines 方法没有返回值。

此时如果我们点开 example.txt 文件会发现依然是空白,没有写入任何字符。其实现在数据还在文件对象的缓冲区里面,要把文件对象关闭,数据才能够写入到文件中。(使用 f.close() 可以关闭文件对象)

f.close()

此时结果:
This is abc. 和 aaa 之间没有 换行符 所以会连着一块。

This is abc.aaa
bbb
cccdddeee

此时如果我们想对这个文件再进行操作,可以使用 model='r+'(r+ 打开一个文件用于读写。文件指针将会放在文件的开头):

f = open('example.txt','r+')

这样的打开的文件对象既可以读取也可以写入。(但是注意 mode=r+ 模式只能打开已经存在的文件,若文件原本不存在,会报错)

f.readable() # 测试读取功能
True
f.writable() # 测试写入功能
True

由于 Python 的文件是支持迭代的,所以我们可以将文件放到 for 语句里面来实现读取

for each in f:
    print(each)
This is abc.aaa

bbb

cccdddeee

此时如果我们使用 read() 方法,什么也读取不出来:

f.read()
''

这是因为文件对象的内部事实上有一个指针(文件指针),这负责指向文件的当前位置,当在文件中读取一个字符的时候,文件指针就会指向下一个字符,直到文件的末尾 EOF (end of file)。前面我们已经使用 for 语句把文件都读完了,所以当前文件指针指向文件的末尾。用 tell() 方法来追踪文件指针:

f.tell() # 第 31 个字符的位置,这个位置其实就是位于文件的末尾
31

我们可以使用 seek() 方法重新移动文件指针:

f.seek(0)
0
f.readline() # readline()  每次读取一行,包括换行符
'This is abc.aaa\n'
f.read() # read() 读取到 EOF 的位置
'bbb\ncccdddeee'

如果我们想在不关闭文件的前提下,将文件内容保存到硬盘中,可以使用 flush() 方法。

f.write('....new line')
f.flush()

可以看到在不关闭文件的情况下,文件内容也写入了

This is abc.aaa
bbb
cccdddeee....new line
truncate() 方法 和 截取

truncate() 方法 :适用于将文件对象截取(截断操作)到指定的位置,如果没有指定 pos 参数,就是截取到文件指针当前指定的位置。

f.truncate(15) 
f.close()

这时再打开文件,就会发现 第15个字符以后的内容就被截掉了

This is abc.aaa

同时我们要注意,另一个常见的错误(有时候可能很致命)就是之前说的 open() 函数,mode='w' 模式(使用单独的写入模式来打开文件)也会出现截断操作。

f = open('example.txt','w')
f.close()

此时再打开文件就会发现原来的内容全部被清空了。




还有一个常见的错误,就是一定要注意文件指针。比如 r+ 模式读写打开文件,且文件指针放在开头。如果我们 r+ 模式读写打开一个已经存在的文件后直接开始写入,可能会覆盖原文件的内容

n=0
while n<5: # 以下代码不论运行几遍,所得的文件最后都只有 aaaaa
    n+=1 
    f = open('example.txt','r+')
    f.write('aaaaa')
    f.close()

上面的代码得到的 .txt 文件,永远都只有:

aaaaa

因为每次 f = open('example.txt','r+') 打开后指针都在文件起始,这时候再 f.write('aaaaa') 只会覆盖得到相同的文件。此时我们再对比 a模式:
mode=a模式:打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。

n=0
while n<5: # 每次打开指针在 EOF,会得到5个 bbbbb,(第一个bbbbb会追加在前面文件的结尾处)
    n+=1 
    f = open('example.txt','a')
    f.write('bbbbb\n')
    f.close()

得到的 .txt 文件

aaaaabbbbb
bbbbb
bbbbb
bbbbb
bbbbb

这时候再使用 r+ 模式,下面这段代码只会改前三个字(指针从开头,写入三个字),后面的不影响:

f = open('example.txt','r+')
f.write('123')
f.close()

结果:

123aabbbbb
bbbbb
bbbbb
bbbbb
bbbbb

路径处理 (P55)

不同操作系统的路径分割符是不一样的,Windows系统使用反斜杠,而其他大多数操作系统则使用斜杠。Windows中的反斜杠本身也是字符串中转义字符的反斜杠,所以要在 Windows 系统上使用反斜杠来分割路径就不得不使用另一条反斜杠来转义反斜杠本身,或者直接使用原始字符串。
这里我们要介绍的就是 pathlib (面向对象的文件系统路径)模块,官方文档:https://docs.python.org/zh-cn/3.12/library/pathlib.html#module-pathlib (小技巧 Ctrl+F 搜索相关内容,这个几乎在所有的软件里都有效)
pathlib模块是从 Python 3.4 才开始有的,它可以让文件和路径操作变得快捷方便,替代了 os.path 模块
一些该模块下常用的方法总结:

命令功能
cwd()获取当前目录的路径
Path()创建路径对象
/连接路径
# 导入模块 
from pathlib import Path
# 获取当前目录的路径
Path.cwd()
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础')
# 创建路径对象
p = Path('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础')
p
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础')
# 连接路径
q = p / 'Floder/abc.txt' # 注意这个路径和文件在我电脑上其实是不存在的
q
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Floder/abc.txt')
r = p/'example.txt' # 注意这个路径是事实存在的
r
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/example.txt')

对于路径对象,一些常用的方法和属性总结和示例:

方法/属性功能
方法-
is_dir()判断一个路径是否为一个文件夹
is_file()判断一个路径是否为一个文件
exists()检测一个路径是否存在
stat()查询文件或文件夹的状态信息
resolve()将相对路径转化成绝对路径
iterdir()获取当前路径下所有子文件和文件夹
mkdir()创建文件夹
open()打开文件(与打开文件的open()函数一样,只是不用再传入第一个路径参数,其他参数是一样的)
rename()修改文件或文件夹的名字
replace()替换指定的文件或文件夹
rmdir()/unlink()删除文件夹/文件
glob()功能强大的查找功能
属性-
name获取路径的最后一个部分
stem获取文件的文件名(无后缀)
suffix获取文件的后缀
parent获取父级目录
parents获取其逻辑祖先路径构成的一个不可变序列(支持索引)
parts将路径的各个组件拆分成元组
# 对于一个存在的文件夹路径:
print('对于一个存在的文件夹路径:')
print('is_dir结果:', p.is_dir())
print('is_file结果:', p.is_file())
print('exists结果: ', p.exists())
# 对于一个不存在的路径:
print('对于一个不存在的路径:')
print('is_dir结果:', q.is_dir())
print('is_file结果:', q.is_file())
print('exists结果: ', q.exists())
# 对于一个存在的文件路径:
print('对于一个存在的文件路径:')
print('is_dir结果:', r.is_dir())
print('is_file结果:', r.is_file())
print('exists结果:', r.exists())
对于一个存在的文件夹路径:
is_dir结果: True
is_file结果: False
exists结果:  True
对于一个不存在的路径:
is_dir结果: False
is_file结果: False
exists结果:  False
对于一个存在的文件路径:
is_dir结果: False
is_file结果: True
exists结果: True
# name and stem 属性
print(p.name)
print(q.stem)
print(p.stem) # 也能运行,但是没有意义
python 基础
abc
python 基础
# suffix 属性 获取文件的后缀
print(q.suffix)
.txt
print(p.suffix) # 用于文件夹上则无效
# parent 获取父级目录
p.parent
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C')
# `parents` 获取其逻辑祖先路径构成的一个不可变序列
p.parents # 获得一个可迭代对象
<WindowsPath.parents>
a = p.parents
for i in a:
    print(i)
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C
C:\Users\rwq119\Desktop\CSDN_帖子
C:\Users\rwq119\Desktop
C:\Users\rwq119
C:\Users
C:\
# `parents` 获取其逻辑祖先路径构成的一个不可变序列 
# 这是支持索引的
print(a[0]) # 父级目录
print(a[1]) # 减一级
print(a[2]) # 减两级
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C
C:\Users\rwq119\Desktop\CSDN_帖子
C:\Users\rwq119\Desktop
# parts 将路径的各个组件拆分成元组
p.parts
('C:\\', 'Users', 'rwq119', 'Desktop', 'CSDN_帖子', '鱼C', 'python 基础')
p.stat()
# 对于一个不存在的路径 比如这里的 q, q.stat() 会报错
os.stat_result(st_mode=16895, st_ino=28147497671144608, st_dev=2852420102, st_nlink=1, st_uid=0, st_gid=0, st_size=4096, st_atime=1723217142, st_mtime=1723217062, st_ctime=1705435031)
p.stat().st_size # 指定的是文件夹的尺寸,单位字节 (4096字节=4kb)
4096

相对路径和绝对路径

绝对路径:是文件真正存在的路径。一个路径从根目录开始,一级一级的指向最终的文件或文件夹。
相对路径:是以当前目录作为基准,进行一级一级的目录推导的路径。使用 . 表示当前所在目录;使用 .. 表示上一级目录

a = Path('./abc.txt')
a
WindowsPath('abc.txt')
a = Path('../abc.txt')
a
WindowsPath('../abc.txt')
# resolve() 将相对路径转化成绝对路径
a.resolve()
WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/abc.txt')
# iterdir() 获取当前路径下所有子文件和文件夹
p.iterdir() # 获得一个生成器
<generator object Path.iterdir at 0x0000012A7C40F6D0>
for i in p.iterdir():
    print(i)
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\.ipynb_checkpoints
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\a
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\data.pkl
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\example.txt
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note10 P40to41.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note11 P42to44.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note12 P45to47.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note13 P48to49.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note14 P50to51.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note15 P52to53.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note16 P54to56.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note8 P34to36.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Note9 P37to39-Copy1.ipynb
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\Untitled - Copy.ipynb
# 收集当前目录下所有文件成一个列表
[i for i in p.iterdir() if i.is_file()]
# 收集所有文件夹 [i for i in p.iterdir() if i.is_dir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/data.pkl'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/example.txt'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note10 P40to41.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note11 P42to44.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note12 P45to47.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note13 P48to49.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note14 P50to51.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note15 P52to53.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note16 P54to56.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note8 P34to36.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note9 P37to39-Copy1.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Untitled - Copy.ipynb')]

修改路径的方法

# mkdir() 创建文件夹
# 新生成一个目录对象:目录/新建的文件夹名
a = p/'floder'
a.mkdir() # 这样就创建了这个新的文件夹
# 查看一下
[i for i in p.iterdir() if i.is_dir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/.ipynb_checkpoints'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/a'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/floder')]

注意, 如果要创建的文件夹已经存在,那么再使用 mkdir 就会报错。这时,可以把 exist_ok 参数改成 True 就可以避免(默认 False)

a.mkdir(exist_ok=True)

注意,如果路径中有存在多个不存在的父级目录,也会报错。可以将 parents 参数改成 True,这样不存在的父级目录也会被一并创建

a = p/'a/b/c/floder'
a.mkdir(exist_ok=True,parents=True)
打开文件 open() 方法

open() 函数一样,只是直接作用与一个文件的路径对象上,不用再额外传入第一个参数,但是其他参数都是一样的。

a = p/'example.txt'
f1 = a.open('w') # 创建的一个文件对象复制到 f1 变量,注意 mode=w 会彻底重置这个 .txt 文件(原有的内容都会被删除,重写)
f1.write('aaaaaaa')
f1.close()
# 现在读取一下文件的内容
f1 = a.open('r+')
print(f1.read())
f1.close()
aaaaaaa
rename() 修改文件或文件夹的名字 & replace() 替换指定的文件或文件夹

rename() 修改文件或文件夹的名字:

# 原来的名字
# p 路径下的文件夹
[i for i in p.iterdir() if i.is_dir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/.ipynb_checkpoints'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/a'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/floder')]
# 我们把名字叫 floder 的文件改名 new_folder
old_name = [i for i in p.iterdir() if i.is_dir()][2]
print(old_name)
new_name = p/'new_folder'
print(new_name)
old_name.rename(new_name) # 返回新文件或文件夹的路径
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\floder
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\new_folder





WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/new_folder')
# 新文件夹
[i for i in p.iterdir() if i.is_dir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/.ipynb_checkpoints'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/a'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/new_folder')]

注意 rename() 方法,新旧名字的两个参数必须都包含路径,否则的话没有包含路径的就会被默认为工作目录下的文件或文件夹。 比如如果新名字没有包含路径,老名字包含路径,就会把原来老的文件或文件夹改名并移动到工作目录下。
replace() 替换指定的文件或文件夹:
rename() 非常类似

# p 路径下目前有
[i for i in p.iterdir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/.ipynb_checkpoints'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/a'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/data.pkl'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/example.txt'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/new_folder'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note10 P40to41.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note11 P42to44.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note12 P45to47.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note13 P48to49.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note14 P50to51.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note15 P52to53.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note16 P54to56.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note8 P34to36.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note9 P37to39-Copy1.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Untitled - Copy.ipynb')]
# 我们进入 new_folder 发现里面啥都没有
new_f = p/'new_folder'
[i for i in new_f.iterdir()]
[]
# 现在我们要把 p 路径下的 example.txt 文件 移动到 new_folder 文件夹里,顺便改名叫 'new_example.txt'
old_place = [i for i in p.iterdir()][2]
print(old_place)
new_place = new_f/'new_example.txt'
print(new_place)
old_place.replace(new_place) # 与 rename() 一样 返回新文件或文件夹的路径
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\data.pkl
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\new_folder\new_example.txt





WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/new_folder/new_example.txt')
# 我们再看 new_folder 里面就有了新的这个文件
[i for i in new_f.iterdir()]
[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/new_folder/new_example.txt')]
rmdir()/unlink() 删除文件夹/文件

注意:当使用 rmdir() 删除文件夹的时候,如果目录不是空的话,无法删除会报错

# 我们可以先删除 new_folder/new_example.txt 文件
a = [i for i in new_f.iterdir()][0]
print(a)
a.unlink()
# 此时再查看 new_folder 下,new_example.txt 文件 已经被删掉
a = [i for i in new_f.iterdir()]
print(a)
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\new_folder\new_example.txt
[]
# 此时我们可以删掉 new_folder 这个文件夹
print(new_f)
new_f.rmdir()
# 此时看 p 目录下没有 new_folder 这个文件夹了
[i for i in p.iterdir()]
C:\Users\rwq119\Desktop\CSDN_帖子\鱼C\python 基础\new_folder





[WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/.ipynb_checkpoints'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/a'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/example.txt'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note10 P40to41.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note11 P42to44.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note12 P45to47.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note13 P48to49.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note14 P50to51.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note15 P52to53.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note16 P54to56.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note8 P34to36.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Note9 P37to39-Copy1.ipynb'),
 WindowsPath('C:/Users/rwq119/Desktop/CSDN_帖子/鱼C/python 基础/Untitled - Copy.ipynb')]
glob() 功能强大的查找功能
# 当前工作目录下的文件
a = Path('.')
[i for i in a.iterdir()]
[WindowsPath('.ipynb_checkpoints'),
 WindowsPath('a'),
 WindowsPath('example.txt'),
 WindowsPath('Note10 P40to41.ipynb'),
 WindowsPath('Note11 P42to44.ipynb'),
 WindowsPath('Note12 P45to47.ipynb'),
 WindowsPath('Note13 P48to49.ipynb'),
 WindowsPath('Note14 P50to51.ipynb'),
 WindowsPath('Note15 P52to53.ipynb'),
 WindowsPath('Note16 P54to56.ipynb'),
 WindowsPath('Note8 P34to36.ipynb'),
 WindowsPath('Note9 P37to39-Copy1.ipynb'),
 WindowsPath('Untitled - Copy.ipynb')]
查找当前目录下 所有 以 .xxx 结尾的文件:
# 查找当前工作目录下 所有 以 .ipynb 结尾的文件
a.glob('*.ipynb') # 返回生成器
<generator object Path.glob at 0x0000012A7C449040>
[i for i in a.glob('*.ipynb')]
[WindowsPath('Note10 P40to41.ipynb'),
 WindowsPath('Note11 P42to44.ipynb'),
 WindowsPath('Note12 P45to47.ipynb'),
 WindowsPath('Note13 P48to49.ipynb'),
 WindowsPath('Note14 P50to51.ipynb'),
 WindowsPath('Note15 P52to53.ipynb'),
 WindowsPath('Note16 P54to56.ipynb'),
 WindowsPath('Note8 P34to36.ipynb'),
 WindowsPath('Note9 P37to39-Copy1.ipynb'),
 WindowsPath('Untitled - Copy.ipynb')]
查找当前目录下的下一级目录, 所有 以 .xxx 结尾的文件:
a.glob('*/*.xxx') # 这里我们没有这种文件,就不演示结果了,`.xxx` 结尾的文件可以按需求更换
<generator object Path.glob at 0x0000012A7C449200>
查找当前目录下的以及该目录下的所有子目录下的, 所有以 .xxx 结尾的文件(递归搜索):
a.glob('**/*.xxx') # 这里我们没有这种文件,就不演示结果了,`.xxx` 结尾的文件可以按需求更换
<generator object Path.glob at 0x0000012A7C4495F0>

永久储存其他内容(P56)

with 语句和上下文管理器

如果不用 with 上下文管理器,对文件的操作为 (1)打开文件;(2)操作文件;(3)关闭文件:

f1 = open('example.txt', 'w') # 创建的一个文件对象复制到 f1 变量,注意 mode=w 会彻底重置这个 .txt 文件(原有的内容都会被删除,重写)
f1.write('aaaaaaa')
f1.close()

如果我们使用 with 上下文管理器:
我们就不需要手动的去关闭文件,文件操作的代码就放到 with 语句的缩进里面就可以

with open('example.txt', 'w') as f1:
    # 在 with 语句的缩进范围里可以来操作文件
    f1.write('aaaaaaa')
# 结束了以后不需要关闭文件

使用上下文管理器最大的优势是能够确保资源的释放(文件的正常关闭)
如果我们使用如下代码: \

f1 = open('example.txt', 'w') 
f1.write('aaaaaaa')
1/0
f1.close()

此时程序会报错,当我们打开 example.txt 文件的时候,里面依然是空空的。这是因为程序执行到 1/0 的时候就会停止,没有执行 f1.close()。我们写入的内容就在文件对象的缓冲区里,并没有存到硬盘里,程序就关闭了。
如果我们改成上下文管理器的形式

with open('example.txt', 'w') as f:
    f1.write('aaaaaaa')
    1/0

执行完毕后,依然会报同样的错误(1/0)。但是打开example.txt 文件的时候,里面有 f1.write('aaaaaaa') 的内容。即,尽管代码运行中出现了错误,但是上下文管理器依然可以确保文件可以正常关闭。

pickle 模块

pickle 模块解决的就是永久存储 Python 对象的问题。它允许你将字符串、列表、字典,这些 Python 对象给保存为文件的形式。
(区别.py 的源文件是打包的源代码,是可以被执行的独立单元。pickle 模块是将 Python 对象序列化,序列化就是将 Python 对象转换成为二进制字节流的过程。)

dump() 函数

示例:

# we would like to save all fowllowing var
a,b,c = 1,2,3
d = 'strstrstr'
e = ['text', 10, 20]
x = {'a1': 100, "a2":"sdf"}

# first import pickle
import pickle
# then save them
with open('data.pkl', 'wb') as f:
    pickle.dump(a,f)
    pickle.dump(b,f)
    pickle.dump(c,f)
    pickle.dump(d,f)
    pickle.dump(e,f)
    pickle.dump(x,f)

注意两点:(1)要保存为 pickle 文件,后缀需要是 .pkl(2)需要以二进制的形式来打开
二进制打开,在 open() 函数里,mode参数:
wb: 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。 如果该文件不存在,创建新文件。一般用于非文本文件如图片等
wb+: 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。 如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
rb: 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。

load() 函数

将存入 .pkl 文件的变量再读取回来

globals().clear() # 先清空这个 python 文件的所有变量

此时如果再调用 a,b,c… 等变量会报错,找不到变量。
我们现在读回这些变量:

# first import pickle
import pickle
# then read them
with open('data.pkl', 'rb') as f:
    a = pickle.load(f)
    b = pickle.load(f)
    c = pickle.load(f)
    d = pickle.load(f)
    e = pickle.load(f)
    x = pickle.load(f)

print(a,b,c,d,e,x,sep='\n')
1
2
3
strstrstr
['text', 10, 20]
{'a1': 100, 'a2': 'sdf'}

注意读取的顺序要和原来存放的顺序一致。
如果觉得重复写代码过于麻烦也可以永远元组打包,读取的时候再解包:

globals().clear() # 先清空这个 python 文件的所有变量
# we would like to save all fowllowing var
a,b,c = 1,2,3
d = 'strstrstr'
e = ['text', 10, 20]
x = {'a1': 100, "a2":"sdf"}

# first import pickle
import pickle
# then save them
with open('data.pkl', 'wb') as f:
    pickle.dump((a,b,c,d,e,x),f)
globals().clear() # 清空这个 python 文件的所有变量
# first import pickle
import pickle
# then read them 
with open('data.pkl', 'rb') as f:
    a,b,c,d,e,x = pickle.load(f)

print(a,b,c,d,e,x,sep='\n')
print(a+100)
1
2
3
strstrstr
['text', 10, 20]
{'a1': 100, 'a2': 'sdf'}
101

附言:
题目:Self-study Python Fish-C Note-16 P54-P56
本文为自学B站上鱼C的python课程随手做的笔记。一些概念和例子我个人为更好的理解做了些查询和补充
因本人水平有限,如有任何问题,欢迎大家批评指正!
原视频链接:https://www.bilibili.com/video/BV1c4411e77t?p=8

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个 Python 代码示例,用于实现 multi-head self-attention: ```python import torch import torch.nn as nn class MultiHeadAttention(nn.Module): def __init__(self, d_model, num_heads): super(MultiHeadAttention, self).__init__() self.num_heads = num_heads self.d_model = d_model self.depth = d_model // num_heads self.query_linear = nn.Linear(d_model, d_model) self.key_linear = nn.Linear(d_model, d_model) self.value_linear = nn.Linear(d_model, d_model) self.output_linear = nn.Linear(d_model, d_model) def forward(self, query, key, value, mask=None): batch_size = query.size() # Linear transformations query = self.query_linear(query) key = self.key_linear(key) value = self.value_linear(value) # Split into heads query = query.view(batch_size * self.num_heads, -1, self.depth) key = key.view(batch_size * self.num_heads, -1, self.depth) value = value.view(batch_size * self.num_heads, -1, self.depth) # Transpose for matrix multiplication query = query.transpose(1, 2) key = key.transpose(1, 2) value = value.transpose(1, 2) # Calculate scores scores = torch.matmul(query, key.transpose(-2, -1)) scores = scores / torch.sqrt(torch.tensor(self.depth).float()) # Apply mask (if provided) if mask is not None: mask = mask.unsqueeze(1) scores = scores.masked_fill(mask == , -1e9) # Softmax attention_weights = nn.Softmax(dim=-1)(scores) # Dropout attention_weights = nn.Dropout(p=.1)(attention_weights) # Multiply by values context = torch.matmul(attention_weights, value) # Reshape and concatenate context = context.transpose(1, 2).contiguous().view(batch_size, -1, self.num_heads * self.depth) # Linear transformation output = self.output_linear(context) return output ``` 希望对你有所帮助! ### 回答2: 下面是使用Python语言实现multi-head self-attention的一个示例代码: ``` import torch import torch.nn as nn import torch.nn.functional as F class MultiHeadSelfAttention(nn.Module): def __init__(self, d_model, num_heads): super(MultiHeadSelfAttention, self).__init__() self.num_heads = num_heads self.d_head = d_model // num_heads self.fc_query = nn.Linear(d_model, d_model) self.fc_key = nn.Linear(d_model, d_model) self.fc_value = nn.Linear(d_model, d_model) self.fc_concat = nn.Linear(d_model, d_model) def forward(self, x): batch_size, seq_len, d_model = x.size() h = self.num_heads # Split input into multiple heads query = self.fc_query(x).view(batch_size, seq_len, h, self.d_head) key = self.fc_key(x).view(batch_size, seq_len, h, self.d_head) value = self.fc_value(x).view(batch_size, seq_len, h, self.d_head) # Compute attention scores scores = torch.matmul(query, key.transpose(-2, -1)) / (self.d_head ** 0.5) attn_weights = F.softmax(scores, dim=-1) # Apply attention weights to value vectors attended_values = torch.matmul(attn_weights, value) attended_values = attended_values.transpose(1, 2).contiguous().view(batch_size, seq_len, -1) # Concatenate and linearly transform attended values output = self.fc_concat(attended_values) return output # 使用示例 d_model = 128 num_heads = 8 seq_len = 10 batch_size = 4 input_tensor = torch.randn(batch_size, seq_len, d_model) attention = MultiHeadSelfAttention(d_model, num_heads) output = attention(input_tensor) print("Input Shape: ", input_tensor.shape) print("Output Shape: ", output.shape) ``` 上述代码定义了一个`MultiHeadSelfAttention`的类,其中`forward`函数实现了multi-head self-attention的计算过程。在使用示例中,我们输入一个大小为`(batch_size, seq_len, d_model)`的张量,经过multi-head self-attention计算后输出一个大小为`(batch_size, seq_len, d_model)`的张量。其中`d_model`表示输入的特征维度,`num_heads`表示attention头的数量。 ### 回答3: 下面是使用Python实现multi-head self-attention示例的代码: ```python import torch import torch.nn as nn class MultiHeadSelfAttention(nn.Module): def __init__(self, embed_size, num_heads): super(MultiHeadSelfAttention, self).__init__() self.embed_size = embed_size self.num_heads = num_heads self.head_size = embed_size // num_heads self.query = nn.Linear(embed_size, embed_size) self.key = nn.Linear(embed_size, embed_size) self.value = nn.Linear(embed_size, embed_size) self.out = nn.Linear(embed_size, embed_size) def forward(self, x): batch_size, seq_len, embed_size = x.size() # Split the embedding into num_heads and reshape x = x.view(batch_size, seq_len, self.num_heads, self.head_size) x = x.permute(0, 2, 1, 3) # Apply linear transformations to obtain query, key, and value query = self.query(x) key = self.key(x) value = self.value(x) # Compute scaled dot product attention scores scores = torch.matmul(query, key.permute(0, 1, 3, 2)) scores = scores / self.head_size**0.5 # Apply softmax to obtain attention probabilities attn_probs = nn.Softmax(dim=-1)(scores) # Apply attention weights to value and sum across heads attended = torch.matmul(attn_probs, value) attended = attended.permute(0, 2, 1, 3) attended = attended.contiguous().view(batch_size, seq_len, self.embed_size) # Apply output linear transformation output = self.out(attended) return output ``` 上述代码中定义了一个名为MultiHeadSelfAttention的类,继承自nn.Module,可以通过指定嵌入大小(embed_size)和头部数量(num_heads)来创建多头自注意力层。在前向传播方法forward中,先通过线性变换将输入张量分别变换为查询(query)、键(key)和值(value)张量。然后计算缩放点积注意力得分,将其作为注意力概率经过softmax函数进行归一化。通过注意力概率权重对值进行加权求和,并应用线性变换得到最终的输出张量。最后返回输出张量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值