Python 数据持久化 - 快速指南


Python 数据持久化 - 简介

Python概述——数据持久化

在使用任何软件应用程序的过程中,用户都会提供一些要处理的数据。可以使用标准输入设备(键盘)或其他设备(例如磁盘文件、扫描仪、摄像头、网线、WiFi连接等)输入数据。

如此接收的数据以各种数据结构(例如变量和对象)的形式存储在计算机的主存储器(RAM)中,直到应用程序运行。此后,RAM 中的存储内容被擦除。

然而,通常希望变量和/或对象的值以这样的方式存储,以便可以在需要时检索它,而不是再次输入相同的数据。

“持久性”一词的意思是“原因消除后结果的持续”。术语数据持久性意味着即使在应用程序结束后它仍然继续存在。因此,存储在诸如磁盘文件之类的非易失性存储介质中的数据是持久数据存储。

在本教程中,我们将探索各种内置和第三方 Python 模块,用于存储和检索各种格式的数据,例如文本文件、CSV、JSON 和 XML 文件以及关系和非关系数据库。

使用Python的内置File对象,可以将字符串数据写入磁盘文件并从中读取。Python 的标准库提供了用于存储和检索各种数据结构(例如 JSON 和 XML)中的序列化数据的模块。

Python 的 DB-API 提供了与关系数据库交互的标准方式。其他第三方 Python 包提供与 NOSQL 数据库(例如 MongoDB 和 Cassandra)的接口功能。

本教程还介绍了 ZODB 数据库,它是 Python 对象的持久化 API。Microsoft Excel 格式是一种非常流行的数据文件格式。在本教程中,我们将学习如何通过 Python 处理 .xlsx 文件。

Python 数据持久化 - 文件 API

Python 使用内置的input()print()函数来执行标准输入/输出操作。input() 函数从标准输入流设备(即键盘)读取字节。

另一方面, print() 函数将数据发送到标准输出流设备,即显示监视器Python程序通过sys模块中定义的标准流对象stdinstdout与这些IO设备进行交互。

input ()函数实际上是 sys.stdin 对象的 readline() 方法的包装。接收来自输入流的所有击键,直到按下“Enter”键。

>>> import sys
>>> x=sys.stdin.readline()
Welcome to TutorialsPoint
>>> x
'Welcome to TutorialsPoint\n'

请注意,readline()函数会留下尾随“\n”字符。还有一个 read() 方法,它从标准输入流读取数据,直到按Ctrl+D字符终止。

>>> x=sys.stdin.read()
Hello
Welcome to TutorialsPoint
>>> x
'Hello\nWelcome to TutorialsPoint\n'

类似地,print()是一个模拟 stdout 对象的 write() 方法的便利函数。

>>> x='Welcome to TutorialsPoint\n'
>>> sys.stdout.write(x)
Welcome to TutorialsPoint
26

正如 stdin 和 stdout 预定义的流对象一样,Python 程序可以从磁盘文件或网络套接字读取数据并向其发送数据。它们也是溪流。任何具有 read() 方法的对象都是输入流。任何具有 write() 方法的对象都是输出流。通过使用内置 open() 函数获取对流对象的引用来建立与流的通信。

open() 函数

这个内置函数使用以下参数 -

f=open(name, mode, buffering)

name 参数,是磁盘文件的名称或字节字符串,mode 是可选的单字符字符串,用于指定要执行的操作类型(读、写、追加等),缓冲参数是 0、1 或 -1 表示缓冲关闭、打开或系统默认设置。

文件打开方式如下表所示。默认模式是“r”

先生编号 参数及说明
1

打开以供阅读(默认)

2

打开写入,首先截断文件

3

X

创建一个新文件并打开它进行写入

4

A

打开进行写入,如果存在则追加到文件末尾

5

二进制模式

6

时间

文本模式(默认)

7

+

打开磁盘文件进行更新(读取和写入)

为了将数据保存到文件中,必须使用“w”模式打开它。

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

该文件对象充当输出流,并且可以访问 write() 方法。write() 方法向该对象发送一个字符串,并存储在其底层的文件中。

string="Hello TutorialsPoint\n"
f.write(string)

关闭流非常重要,以确保缓冲区中剩余的任何数据都完全传输到其中。

file.close()

尝试使用任何测试编辑器(例如记事本)打开“test.txt”以确认文件创建成功。

要以编程方式读取“test.txt”的内容,必须以“r”模式打开它。

f=open('test.txt','r')

该对象充当输入流。Python 可以使用read()方法从流中获取数据。

string=f.read()
print (string)

文件的内容显示在 Python 控制台上。File 对象还支持readline()方法,该方法能够读取字符串直到遇到 EOF 字符。

但是,如果以“w”模式打开同一文件以在其中存储其他文本,则较早的内容将被删除。每当以写权限打开文件时,都会将其视为新文件。要将数据添加到现有文件,请使用“a”作为附加模式。

f=open('test.txt','a')
f.write('Python Tutorials\n')

现在的文件包含较早的和新添加的字符串。文件对象还支持writelines()方法将列表对象中的每个字符串写入文件。

f=open('test.txt','a')
lines=['Java Tutorials\n', 'DBMS tutorials\n', 'Mobile development tutorials\n']
f.writelines(lines)
f.close()

例子

readlines ()方法返回一个字符串列表,每个字符串代表文件中的一行。也可以逐行读取文件,直到到达文件末尾。

f=open('test.txt','r')
while True:
   line=f.readline()
   if line=='' : break
   print (line, end='')
f.close()

输出

Hello TutorialsPoint
Python Tutorials
Java Tutorials
DBMS tutorials
Mobile development tutorials

二进制模式

默认情况下,对文件对象的读/写操作是对文本字符串数据执行的。如果我们想处理不同其他类型的文件,例如媒体(mp3)、可执行文件(exe)、图片(jpg)等,我们需要在读/写模式下添加“b”前缀。

以下语句将字符串转换为字节并写入文件。

f=open('test.bin', 'wb')
data=b"Hello World"
f.write(data)
f.close()

也可以使用encode() 函数将文本字符串转换为字节。

data="Hello World".encode('utf-8')

我们需要使用“rb”模式来读取二进制文件。read() 方法的返回值在打印之前首先被解码。

f=open('test.bin', 'rb')
data=f.read()
print (data.decode(encoding='utf-8'))

为了将整数数据写入二进制文件,应通过to_bytes()方法将整数对象转换为字节。

n=25
n.to_bytes(8,'big')
f=open('test.bin', 'wb')
data=n.to_bytes(8,'big')
f.write(data)

要从二进制文件读回,请通过 from_bytes() 函数将 read() 函数的输出转换为整数。

f=open('test.bin', 'rb')
data=f.read()
n=int.from_bytes(data, 'big')
print (n)

对于浮点数据,我们需要使用Python标准库中的struct模块。

import struct
x=23.50
data=struct.pack('f',x)
f=open('test.bin', 'wb')
f.write(data)

从 read() 函数中解压字符串,以从二进制文件中检索浮点数据。

f=open('test.bin', 'rb')
data=f.read()
x=struct.unpack('f', data)
print (x)

同时读/写

当打开文件进行写入(使用“w”或“a”)时,无法读取该文件,反之亦然。这样做会引发 UnSupportedOperation 错误。我们需要在进行其他操作之前关闭该文件。

为了同时执行这两个操作,我们必须在模式参数中添加“+”字符。因此,“w+”或“r+”模式允许使用 write() 和 read() 方法,而无需关闭文件。File 对象还支持seek() 函数来将流倒回到任何所需的字节位置。

f=open('test.txt','w+')
f.write('Hello world')
f.seek(0,0)
data=f.read()
print (data)
f.close()

下表总结了可用于类似文件对象的所有方法。

先生编号 方法及说明
1

关闭()

关闭文件。关闭的文件无法再读取或写入。

2

冲洗()

刷新内部缓冲区。

3

文件编号()

返回整数文件描述符。

4

下一个()

每次调用时返回文件的下一行。在 Python 3 中使用 next() 迭代器。

5

读取([大小])

从文件中读取最多 size 字节(如果在获取 size 字节之前读取达到 EOF,则读取次数较少)。

6

读行([大小])

从文件中读取一整行。尾随换行符保留在字符串中。

7

读取行([大小提示])

使用 readline() 读取直到 EOF 并返回包含行的列表。

8

寻求(偏移[,从哪里])

设置文件的当前位置。0-开始 1-当前 2-结束。

9

寻求(偏移[,从哪里])

设置文件的当前位置。0-开始 1-当前 2-结束。

10

告诉()

返回文件的当前位置

11

截断([大小])

截断文件的大小。

12

写(字符串)

将字符串写入文件。没有返回值。

使用 os 模块进行文件处理

除了open()函数返回的 File 对象之外,还可以使用 Python 的内置库执行文件 IO 操作,该库具有 os 模块,该模块提供有用的操作系统相关函数。这些函数对文件执行低级读/写操作。

os 模块中的open ()函数与内置 open() 类似。但是,它不返回文件对象,而是返回文件描述符,即与打开的文件相对应的唯一整数。文件描述符的值 0、1 和 2 代表 stdin、stdout 和 stderr 流。从 2 开始,其他文件将被赋予增量文件描述符。

open()内置函数一样,os.open()函数也需要指定文件访问模式。下表列出了 os 模块中定义的各种模式。

先生。 操作系统模块及描述
1

os.O_RDONLY

仅供阅读

2

os.O_WRONLY

仅供写入

3

os.O_RDWR

开放阅读和写作

4

os.O_NONBLOCK

打开时不要阻塞

5

os.O_APPEND

每次写入时追加

6

os.O_CREAT

如果文件不存在则创建

7

os.O_TRUNC

将大小截断为 0

8

os.O_EXCL

如果创建且文件存在则出错

要打开一个新文件并在其中写入数据,请通过插入管道 (|) 运算符来指定O_WRONLYO_CREAT模式。os.open() 函数返回一个文件描述符。

f=os.open("test.dat", os.O_WRONLY|os.O_CREAT)

需要注意的是,数据是以字节串的形式写入磁盘文件的。因此,使用前面的encode()函数将普通字符串转换为字节字符串。

data="Hello World".encode('utf-8')

os 模块中的 write() 函数接受该字节字符串和文件描述符。

os.write(f,data)

不要忘记使用 close() 函数关闭文件。

os.close(f)

要使用 os.read() 函数读取文件内容,请使用以下语句:

f=os.open("test.dat", os.O_RDONLY)
data=os.read(f,20)
print (data.decode('utf-8'))

请注意,os.read() 函数需要文件描述符和要读取的字节数(字节字符串的长度)。

如果要打开文件进行同时读/写操作,请使用 O_RDWR 模式。下表列出了 os 模块中重要的文件操作相关函数。

先生编号 功能及说明
1

os.close(fd)

关闭文件描述符。

2

os.open(文件, 标志[, 模式])

打开文件并根据 flags 设置各种标志,并根据 mode 可能设置其模式。

3

os.read(fd, n)

从文件描述符 fd 中最多读取 n 个字节。返回包含读取字节的字符串。如果已到达 fd 引用的文件末尾,则返回空字符串。

4

os.write(fd, str)

将字符串 str 写入文件描述符 fd。返回实际写入的字节数。

Python数据持久化——对象序列化

Python 的内置 open() 函数返回的内置文件对象有一个重要的缺点。当以“w”模式打开时,write() 方法仅接受字符串对象。

这意味着,如果您有以任何非字符串形式表示的数据、内置类(数字、字典、列表或元组)或其他用户定义类的对象,则无法将其直接写入文件。在编写之前,您需要将其转换为字符串表示形式。

numbers=[10,20,30,40]
   file=open('numbers.txt','w')
   file.write(str(numbers))
   file.close()

对于二进制文件,write()方法的参数必须是字节对象。例如,整数列表通过bytearray()函数转换为字节,然后写入文件。

numbers=[10,20,30,40]
   data=bytearray(numbers)
   file.write(data)
   file.close()

要以相应的数据类型从文件中读回数据,需要进行反向转换。

file=open('numbers.txt','rb')
   data=file.read()
   print (list(data))

这种将对象手动转换为字符串或字节格式(反之亦然)的方法非常麻烦且乏味。可以将 Python 对象的状态以字节流的形式直接存储到文件或内存流中并检索到其原始状态。这个过程称为序列化和反序列化。

Python 的内置库包含用于序列化和反序列化过程的各种模块。

先生。 名称和描述
1

泡菜

Python 特定的序列化库

2

元帅

内部用于序列化的库

3

搁置

Pythonic 对象持久化

4

数据库管理

提供 Unix 数据库接口的库

5

数据集

用于将 Python 数据存储和检索为 CSV 格式的库

6

json

用于序列化为通用 JSON 格式的库

Python 数据持久化 - Pickle 模块

Python 的序列化和反序列化术语分别是 pickling 和 unpickling。Python 库中的 pickle 模块使用非常 Python 特定的数据格式。因此,非 Python 应用程序可能无法正确反序列化 pickle 数据。还建议不要从未经验证的来源中解封数据。

序列化(腌制)的数据可以存储在字节字符串或二进制文件中。该模块定义了dumps()loads()函数来使用字节字符串来pickle 和unpickle 数据。对于基于文件的进程,该模块具有dump()load()函数。

Python 的 pickle 协议是用于在二进制数据中构造和解构 Python 对象的约定。目前,pickle 模块定义了 5 种不同的协议,如下所示:

先生。 名称和描述
1

协议版本0

原始的“人类可读”协议向后兼容早期版本。

2

协议版本1

旧的二进制格式也与早期版本的 Python 兼容。

3

协议版本2

Python 2.3 中引入的新样式类提供了高效的 p​​ickle。

4

协议版本3

Python 3.0 中添加。当需要与其他 Python 3 版本兼容时推荐使用。

5

协议版本4

在 Python 3.4 中添加。它增加了对非常大的对象的支持

例子

pickle 模块由 dumps() 函数组成,该函数返回 pickle 数据的字符串表示形式。

from pickle import dump
dct={"name":"Ravi", "age":23, "Gender":"M","marks":75}
dctstring=dumps(dct)
print (dctstring)

输出

b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x04\x00\x00\x00Raviq\x02X\x03\x00\x00\x00ageq\x03K\x17X\x06\x00\x00\x00Genderq\x04X\x01\x00\x00\x00Mq\x05X\x05\x00\x00\x00marksq\x06KKu.

例子

使用loads()函数,对字符串进行unpickle并获取原始字典对象。

from pickle import load
dct=loads(dctstring)
print (dct)

输出

{'name': 'Ravi', 'age': 23, 'Gender': 'M', 'marks': 75}

Pickled 对象还可以使用 dump() 函数持久存储在磁盘文件中,并使用 load() 函数检索。

import pickle
f=open("data.txt","wb")
dct={"name":"Ravi", "age":23, "Gender":"M","marks":75}
pickle.dump(dct,f)
f.close()

#to read
import pickle
f=open("data.txt","rb")
d=pickle.load(f)
print (d)
f.close()

pickle 模块还以PicklerUnpickler类的形式为序列化机制提供面向对象的 API 。

如上所述,就像Python中的内置对象一样,用户定义类的对象也可以持久序列化在磁盘文件中。在下面的程序中,我们定义一个 User 类,以姓名和手机号码作为其实例属性。除了 __init__() 构造函数之外,该类还重写 __str__() 方法,该方法返回其对象的字符串表示形式。

class User:
   def __init__(self,name, mob):
      self.name=name
      self.mobile=mob
   def __str__(self):
return ('Name: {} mobile: {} '. format(self.name, self.mobile))

为了在文件中pickle上述类的对象,我们使用pickler类及其dump()方法。

from pickle import Pickler
user1=User('Rajani', 'raj@gmail.com', '1234567890')
file=open('userdata','wb')
Pickler(file).dump(user1)
Pickler(file).dump(user2)
file.close()

相反,Unpickler 类具有 load() 方法来检索序列化对象,如下所示 -

from pickle import Unpickler
file=open('usersdata','rb')
user1=Unpickler(file).load()
print (user1)

Python 数据持久化 - Marshal 模块

Python标准库中marshal模块的对象序列化功能与pickle模块类似。但是,该模块不用于通用数据。另一方面,Python 本身使用它进行 Python 的内部对象序列化,以支持对 Python 模块(.pyc 文件)的编译版本的读/写操作。

marshal 模块使用的数据格式在 Python 版本之间不兼容。因此,一个版本的已编译 Python 脚本(.pyc 文件)很可能无法在另一版本上执行。

就像 pickle 模块一样,marshal 模块也定义了 load() 和 dump() 函数,用于从文件中读取和写入编组对象。

倾倒()

此函数将支持的 Python 对象的字节表示形式写入文件。文件本身是一个具有写权限的二进制文件

加载()

该函数从二进制文件中读取字节数据并将其转换为Python对象。

以下示例演示了使用 dump() 和 load() 函数来处理 Python 的代码对象,这些对象用于存储预编译的 Python 模块。

该代码使用内置的compile()函数从嵌入Python指令的源字符串构建代码对象。

compile(source, file, mode)

文件参数应该是从中读取代码的文件。如果不是从文件中读取,则传递任意字符串。

如果源包含语句序列,则模式参数为“exec”;如果存在单个表达式,则模式参数为“eval”;如果包含单个交互式语句,则模式参数为“single”。

然后使用 dump() 函数将编译代码对象存储在 .pyc 文件中。

import marshal
script = """
a=10
b=20
print ('addition=',a+b)
"""
code = compile(script, "script", "exec")
f=open("a.pyc","wb")
marshal.dump(code, f)
f.close()

要反序列化,.pyc 文件中的对象使用 load() 函数。由于它返回一个代码对象,因此可以使用另一个内置函数 exec() 运行它。

import marshal
f=open("a.pyc","rb")
data=marshal.load(f)
exec (data)

Python数据持久化——Shelve模块

Python标准库中的shelve模块提供了简单而有效的对象持久化机制。该模块中定义的架子对象是类似字典的对象,持久存储在磁盘文件中。这将创建一个类似于 UNIX 类系统上的 dbm 数据库的文件。

架子词典有一定的限制。在这个特殊的字典对象中,只有字符串数据类型可以用作键,而任何可picklable Python对象都可以用作值。

shelve 模块定义了三个类,如下 -

先生编号 搁架模块及描述
1

架子

这是架实现的基类。它是用类似字典的对象初始化的。

2

BsdDb架子

这是 Shelf 类的子类。传递给其构造函数的 dict 对象必须支持first()、next()、previous()、last() 和set_location() 方法。

3

数据库文件名Shelf

这也是 Shelf 的子类,但接受文件名作为其构造函数的参数,而不是 dict 对象。

shelve 模块中定义的 open() 函数返回DbfilenameShelf对象。

open(filename, flag='c', protocol=None, writeback=False)

文件名参数被分配给创建的数据库。标志参数的默认值为“c”,用于读/写访问。其他标志是“w”(只写)、“r”(只读)和“n”(新的读/写)。

序列化本身由 pickle 协议控制,默认为无。最后一个参数写回参数默认为 false。如果设置为 true,则缓存访问的条目。每次访问都会调用sync()和close()操作,因此过程可能会很慢。

以下代码创建一个数据库并在其中存储字典条目。

import shelve
s=shelve.open("test")
s['name']="Ajay"
s['age']=23
s['marks']=75
s.close()

这将在当前目录中创建 test.dir 文件并以哈希形式存储键值数据。Shelf 对象有以下可用方法 -

先生。 方法与说明
1

关闭()

同步并关闭持久 dict 对象。

2

同步()

如果在写回设置为 True 的情况下打开架子,则写回缓存中的所有条目。

3

得到()

返回与键关联的值

4

项目()

元组列表 – 每个元组都是键值对

5

键()

货架钥匙列表

6

流行音乐()

删除指定的key并返回对应的值。

7

更新()

从另一个字典/可迭代更新架子

8

值()

货架价值清单

访问架子中特定键的值 -

s=shelve.open('test')
print (s['age']) #this will print 23
   s['age']=25
print (s.get('age')) #this will print 25
s.pop('marks') #this will remove corresponding k-v pair

与内置字典对象一样,items()、keys() 和values() 方法返回视图对象。

print (list(s.items()))
[('name', 'Ajay'), ('age', 25), ('marks', 75)]  

print (list(s.keys()))
['name', 'age', 'marks']

print (list(s.values()))
['Ajay', 25, 75]

要将另一个字典的项目与架子合并,请使用 update() 方法。

d={'salary':10000, 'designation':'manager'}
s.update(d)
print (list(s.items()))

[('name', 'Ajay'), ('age', 25), ('salary', 10000), ('designation', 'manager')]

Python数据持久化——dbm包

dbm 包提供了一个类似于 DBM 风格数据库接口的字典。DBM 代表数据库管理器。这是由 UNIX(和类 UNIX)操作系统使用的。dbbm 库是 Ken Thompson 编写的一个简单的数据库引擎。这些数据库使用二进制编码的字符串对象作为键和值。

数据库使用固定大小的存储桶中的单个键(主键)存储数据,并使用散列技术来实现按键快速检索数据。

dbm 包包含以下模块 -

  • dbm.gnu模块是由 GNU 项目实现的 DBM 库版本的接口。

  • dbm.ndbm模块提供了 UNIX nbdm 实现的接口。

  • dbm.dumb用作事件中的后备选项,未找到其他 dbm 实现。这不需要外部依赖项,但比其他方法慢。

>>> dbm.whichdb('mydbm.db')
'dbm.dumb'
>>> import dbm
>>> db=dbm.open('mydbm.db','n')
>>> db['name']=Raj Deshmane'
>>> db['address']='Kirtinagar Pune'
>>> db['PIN']='431101'
>>> db.close()

open() 函数允许模式这些标志 -

先生。 价值与意义
1

'r'

打开现有数据库以只读方式(默认)

2

'w'

打开现有数据库进行读写

3

'C'

打开数据库进行读写,不存在则创建

4

'n'

始终创建一个新的空数据库,打开以进行读写

dbm 对象是一个类似字典的对象,就像架子对象一样。因此,可以执行所有字典操作。dbm 对象可以调用 get()、pop()、append() 和 update() 方法。以下代码使用“r”标志打开“mydbm.db”,并迭代键值对的集合。

>>> db=dbm.open('mydbm.db','r')
>>> for k,v in db.items():
   print (k,v)
b'name' : b'Raj Deshmane'
b'address' : b'Kirtinagar Pune'
b'PIN' : b'431101'

Python 数据持久化 - CSV 模块

CSV 代表逗号分隔值。此文件格式是在数据库中的电子表格和数据表中导出/导入数据时常用的数据格式。作为 PEP 305 的结果,csv 模块被合并到 Python 的标准库中。它提供了根据 PEP 305 的建议对 CSV 文件执行读/写操作的类和方法。

CSV 是 Microsoft Excel 电子表格软件的首选导出数据格式。但是,csv 模块也可以处理其他方言表示的数据。

CSV API 接口由以下编写器和读取器类组成 -

作家()

csv 模块中的此函数返回一个编写器对象,该对象将数据转换为分隔字符串并存储在文件对象中。该函数需要一个具有写权限的文件对象作为参数。文件中写入的每一行都会发出一个换行符。为了防止行间出现额外的空格,换行参数设置为“”。

writer 类有以下方法 -

写入行()

此方法将项目写入可迭代对象(列表、元组或字符串)中,并用逗号字符分隔它们。

写入行()

此方法采用可迭代列表作为参数,并将每个项目作为逗号分隔的项目行写入文件中。

例子

以下示例显示 writer() 函数的使用。首先以“w”模式打开一个文件。该文件用于获取writer对象。然后使用 writerow() 方法将元组列表中的每个元组写入文件。

import csv
   persons=[('Lata',22,45),('Anil',21,56),('John',20,60)]
   csvfile=open('persons.csv','w', newline='')
   obj=csv.writer(csvfile)
   for person in persons:
      obj.writerow(person)
csvfile.close()

输出

这将在当前目录中创建“persons.csv”文件。它将显示以下数据。

Lata,22,45
Anil,21,56
John,20,60

我们可以使用 writerows() 方法,而不是迭代列表来单独写入每一行。

csvfile=open('persons.csv','w', newline='')
persons=[('Lata',22,45),('Anil',21,56),('John',20,60)]
   obj=csv.writer(csvfile)
   obj.writerows(persons)
   obj.close()

读者()

此函数返回一个读取器对象,该对象返回csv 文件中行的迭代器。使用常规 for 循环,文件中的所有行都显示在以下示例中 -

例子

csvfile=open('persons.csv','r', newline='')
   obj=csv.reader(csvfile)
   for row in obj:
      print (row)

输出

['Lata', '22', '45']
['Anil', '21', '56']
['John', '20', '60']

读取器对象是一个迭代器。因此,它支持 next() 函数,该函数也可用于显示 csv 文件中的所有行,而不是for 循环

csvfile=open('persons.csv','r', newline='')
   obj=csv.reader(csvfile)
   while True:
   try:
      row=next(obj)
      print (row)
   except StopIteration:
      break

如前所述,csv 模块使用 Excel 作为其默认语言。csv 模块还定义了方言类。Dialect 是一组用于实现 CSV 协议的标准。可用的方言列表可以通过 list_dialects() 函数获得。

>>> csv.list_dialects()
['excel', 'excel-tab', 'unix']

除了可迭代之外,csv 模块还可以将字典对象导出到 CSV 文件并读取它以填充 Python 字典对象。为此,该模块定义了以下类 -

字典编写器()

该函数返回一个 DictWriter 对象。它与 writer 对象类似,但行映射到字典对象。该函数需要一个具有写入权限的文件对象和字典中使用的键列表作为字段名参数。这用于将文件中的第一行写入作为标题。

写头()

此方法将字典中的键列表作为逗号分隔行写入文件中的第一行。

在以下示例中,定义了字典项列表。列表中的每一项都是一本字典。使用 writrows() 方法,它们以逗号分隔的方式写入文件。

persons=[
   {'name':'Lata', 'age':22, 'marks':45}, 
   {'name':'Anil', 'age':21, 'marks':56}, 
   {'name':'John', 'age':20, 'marks':60}
]
csvfile=open('persons.csv','w', newline='')
fields=list(persons[0].keys())
obj=csv.DictWriter(csvfile, fieldnames=fields)
obj.writeheader()
obj.writerows(persons)
csvfile.close()

person.csv 文件显示以下内容 -

name,age,marks
Lata,22,45
Anil,21,56
John,20,60

字典阅读器()

此函数从基础 CSV 文件返回一个 DictReader 对象。与 reader 对象一样,它也是一个迭代器,使用它检索文件的内容。

csvfile=open('persons.csv','r', newline='')
obj=csv.DictReader(csvfile)

该类提供 fieldnames 属性,返回用作文件头的字典键。

print (obj.fieldnames)
['name', 'age', 'marks']

使用 DictReader 对象上的循环来获取单个字典对象。

for row in obj:
   print (row)

这会产生以下输出 -

OrderedDict([('name', 'Lata'), ('age', '22'), ('marks', '45')])
OrderedDict([('name', 'Anil'), ('age', '21'), ('marks', '56')])
OrderedDict([('name', 'John'), ('age', '20'), ('marks', '60')])

要将 OrderedDict 对象转换为普通字典,我们必须首先从 collections 模块导入 OrderedDict。

from collections import OrderedDict
   r=OrderedDict([('name', 'Lata'), ('age', '22'), ('marks', '45')])
   dict(r)
{'name': 'Lata', 'age': '22', 'marks': '45'}

Python 数据持久化 - JSON 模块

JSON 代表JavaScript 对象表示法。它是一种轻量级数据交换格式。它是一种独立于语言和跨平台的文本格式,受到许多编程语言的支持。此格式用于 Web 服务器和客户端之间的数据交换。

JSON 格式类似于 pickle。然而,pickle 序列化是 Python 特有的,而 JSON 格式是由许多语言实现的,因此已成为通用标准。Python 标准库中 json 模块的功能和接口类似于 pickle 和 marshal 模块。

就像pickle模块一样,json模块也提供了dumps()loads()函数,用于将Python对象序列化为JSON编码字符串,并且dump()load()函数将序列化的Python对象写入文件或从文件读取。

  • dumps() - 此函数将对象转换为 JSON 格式。

  • load() - 该函数将 JSON 字符串转换回 Python 对象。

以下示例演示了这些函数的基本用法 -

import json
   data=['Rakesh',{'marks':(50,60,70)}]
   s=json.dumps(data)
json.loads(s)

dumps() 函数可以采用可选的 sort_keys 参数。默认情况下,它是 False。如果设置为 True,字典键将按排序顺序显示在 JSON 字符串中。

dumps() 函数还有另一个名为 indent 的可选参数,它接受一个数字作为值。它决定 json 字符串格式化表示的每段长度,类似于打印输出。

json模块也有与上述功能相对应的面向对象的API。模块中定义了两个类 - JSONEncoder 和 JSONDecoder。

JSONEncoder 类

该类的对象是Python数据结构的编码器。每个 Python 数据类型都会转换为相应的 JSON 类型,如下表所示 -

Python JSON
词典 目的
列表、元组 大批
斯特 细绳
int、float、int 和 float 派生的枚举 数字
真的 真的
错误的 错误的
没有任何 无效的

JSONEncoder 类由 JSONEncoder() 构造函数实例化。编码器类中定义了以下重要方法 -

先生。 方法与说明
1

编码()

将Python对象序列化为JSON格式

2

迭代编码()

对对象进行编码并返回一个迭代器,生成对象中每个项目的编码形式。

3

缩进

确定编码字符串的缩进级别

4

排序键

为 true 或 false 以使键按排序顺序显示或不按排序顺序显示。

5

检查循环

如果为 True,则检查容器类型对象中的循环引用

以下示例对 Python 列表对象进行编码。

e=json.JSONEncoder()
e.encode(data)

JSONDecoder 类

此类的对象有助于将 json 字符串解码回 Python 数据结构。该类的主要方法是decode()。以下示例代码从前面步骤中的编码字符串中检索 Python 列表对象。

d=json.JSONDecoder()
d.decode(s)

json 模块定义了load()dump()函数,用于将 JSON 数据写入类似文件的对象(可以是磁盘文件或字节流),并从中读取数据。

倾倒()

此函数将 JSON 格式的 Python 对象数据写入文件。该文件必须以“w”模式打开。

import json
data=['Rakesh', {'marks': (50, 60, 70)}]
   fp=open('json.txt','w')
   json.dump(data,fp)
   fp.close()

此代码将在当前目录中创建“json.txt”。它显示的内容如下 -

["Rakesh", {"marks": [50, 60, 70]}]

加载()

此函数从文件加载 JSON 数据并从中返回 Python 对象。该文件必须以读取权限打开(应具有“r”模式)。

例子

fp=open('json.txt','r')
   ret=json.load(fp)
   print (ret)
   fp.close()

输出

['Rakesh', {'marks': [50, 60, 70]}]

json.tool模块还有一个命令行界面,可以验证文件中的数据并以漂亮的格式打印 JSON 对象。

C:\python37>python -m json.tool json.txt
[
   "Rakesh",   
   {
      "marks": [
         50,
         60,
         70
      ]
   }
]

Python 数据持久性 - XML 解析器

XML 是可扩展标记语言的缩写。它是一种可移植、开源和跨平台语言,非常类似于 HTML 或 SGML,并受到万维网联盟的推荐。

它是一种众所周知的数据交换格式,被大量应用程序使用,例如 Web 服务、办公工具和面向服务的架构(SOA)。XML 格式既是机器可读的,也是人类可读的。

标准 Python 库的 xml 包包含以下用于 XML 处理的模块 -

先生。 模块和描述
1

xml.etree.ElementTree

ElementTree API,一个简单且轻量级的 XML 处理器

2

xml.dom

DOM API 定义

3

xml.dom.minidom

一个最小的 DOM 实现

4

xml.sax

SAX2接口实现

5

xml.parsers.expat

Expat 解析器绑定

XML 文档中的数据以树状分层格式排列,从根和元素开始。每个元素都是树中的单个节点,并且具有包含在 <> 和 </> 标记中的属性。可以将一个或多个子元素分配给每个元素。

以下是 XML 文档的典型示例 -

<?xml version = "1.0" encoding = "iso-8859-1"?>
<studentlist>
   <student>
      <name>Ratna</name>
      <subject>Physics</subject>
      <marks>85</marks>
   </student>
   <student>
      <name>Kiran</name>
      <subject>Maths</subject>
      <marks>100</marks>
   </student>
   <student>
      <name>Mohit</name>
      <subject>Biology</subject>
      <marks>92</marks>
   </student>
</studentlist>

使用ElementTree模块时,第一步是设置树的根元素。每个元素都有一个标签和 attrib,它是一个 dict 对象。对于根元素,attrib 是一个空字典。

import xml.etree.ElementTree as xmlobj
root=xmlobj.Element('studentList')

现在,我们可以在根元素下添加一个或多个元素。每个元素对象可能有SubElements。每个子元素都有一个属性和文本属性。

student=xmlobj.Element('student')
   nm=xmlobj.SubElement(student, 'name')
   nm.text='name'
   subject=xmlobj.SubElement(student, 'subject')
   nm.text='Ratna'
   subject.text='Physics'
   marks=xmlobj.SubElement(student, 'marks')
   marks.text='85'

使用append() 方法将这个新元素附加到根。

root.append(student)

使用上述方法根据需要附加任意数量的元素。最后,根元素对象被写入文件。

tree = xmlobj.ElementTree(root)
   file = open('studentlist.xml','wb')
   tree.write(file)
   file.close()

现在,我们看看如何解析 XML 文件。为此,构建文档树,并在 ElementTree 构造函数中将其名称作为文件参数。

tree = xmlobj.ElementTree(file='studentlist.xml')

树对象有getroot()方法来获取根元素, getchildren() 返回其下面的元素列表。

root = tree.getroot()
children = root.getchildren()

通过迭代每个子节点的子元素集合来构造每个子元素对应的字典对象。

for child in children:
   student={}
   pairs = child.getchildren()
   for pair in pairs:
      product[pair.tag]=pair.text

然后将每个字典附加到返回字典对象的原始列表的列表中。

SAX是事件驱动的 XML 解析的标准接口。使用 SAX 解析 XML 需要通过子类化 xml.sax.ContentHandler 来实现 ContentHandler。您注册感兴趣事件的回调,然后让解析器继续处理文档。

当您的文档很大或有内存限制时,SAX 非常有用,因为它会在从磁盘读取文件时解析文件,因此整个文件永远不会存储在内存中。

文档对象模型

(DOM) API 是万维网联盟的推荐标准。在这种情况下,整个文件被读入内存并以分层(基于树)的形式存储,以表示 XML 文档的所有功能。

SAX,速度不如 DOM,文件较大。另一方面,如果在许多小文件上使用 DOM,则可能会杀死资源。SAX 是只读的,而 DOM 允许更改 XML 文件。

Python 数据持久化 - Plistlib 模块

plist格式主要由MAC OS X使用。这些文件基本上都是XML文档。它们存储和检索对象的属性。Python 库包含 plist 模块,用于读取和写入“属性列表”文件(它们通常具有 .plist 扩展名)。

plistlib模块在某种意义上与其他序列化库或多或少相似,它还提供了用于 Python 对象的字符串表示的 dumps() 和 load() 函数以及用于磁盘操作的 load() 和 dump() 函数。

以下字典对象维护属性(键)和相应的值 -

proplist = {
   "name" : "Ganesh",
   "designation":"manager",
   "dept":"accts",
   "salary" : {"basic":12000, "da":4000, "hra":800}
}

为了将这些属性写入磁盘文件,我们调用 plist 模块中的 dump() 函数。

import plistlib
fileName=open('salary.plist','wb')
plistlib.dump(proplist, fileName)
fileName.close()

相反,要读回属性值,请使用 load() 函数,如下所示 -

fp= open('salary.plist', 'rb')
pl = plistlib.load(fp)
print(pl)

Python数据持久化-Sqlite3模块

CSV、JSON、XML 等文件的一个主要缺点是它们对于随机访问和事务处理不是很有用,因为它们本质上基本上是非结构化的。因此,修改内容变得非常困难。

这些平面文件不适合客户端-服务器环境,因为它们缺乏异步处理能力。使用非结构化数据文件会导致数据冗余和不一致。

这些问题可以通过使用关系数据库来克服。数据库是有组织的数据集合,用于消除冗余和不一致并保持数据完整性。关系数据库模型非常流行。

它的基本概念是在实体表中排列数据(称为关系)。实体表结构提供一个属性,该属性的值对于每一行都是唯一的。这样的属性称为“主键”

当一个表的主键出现在其他表的结构中时,它被称为“外键”,这构成了两者之间关系的基础。基于这个模型,目前有许多流行的 RDBMS 产品可用 -

  • 数据库管理
  • MySQL
  • PostgreSQL
  • 微软SQL服务器2000
  • 信息系统
  • 英特贝斯
  • 甲骨文
  • 赛贝斯
  • SQLite

SQLite 是一种轻量级关系数据库,可用于多种应用程序。它是一个独立、无服务器、零配置、事务性 SQL 数据库引擎。整个数据库是一个文件,可以放置在文件系统中的任何位置。它是一款开源软件,占用空间非常小,并且零配置。它广泛用于嵌入式设备、物联网和移动应用程序。

所有关系数据库都使用 SQL 来处理表中的数据。然而,早些时候,这些数据库中的每一个都曾经借助特定于数据库类型的Python模块与Python应用程序连接。

因此,他们之间缺乏兼容性。如果用户想要更换不同的数据库产品,这将是很困难的。这一不兼容问题已通过提出“Python 增强提案 (PEP 248)”来解决,以推荐与关系数据库(称为 DB-API)的一致接口。最新的建议称为DB-API版本 2.0。(PEP 249)

Python 的标准库由 sqlite3 模块组成,该模块是一个符合 DB-API 的模块,用于通过 Python 程序处理 SQLite 数据库。本章介绍 Python 与 SQLite 数据库的连接。

如前所述,Python 以 sqlite3 模块的形式内置了对 SQLite 数据库的支持。对于其他数据库,必须在 pip 实用程序的帮助下安装相应的 DB-API 兼容的 Python 模块。例如,要使用MySQL数据库,我们需要安装PyMySQL模块。

pip install pymysql

DB-API 建议执行以下步骤 -

  • 使用connect()函数与数据库建立连接并获取连接对象。

  • 调用连接对象的cursor()方法来获取游标对象。

  • 形成由要执行的 SQL 语句组成的查询字符串。

  • 通过调用execute()方法执行所需的查询。

  • 关闭连接。

import sqlite3
db=sqlite3.connect('test.db')

这里,db是代表test.db的连接对象。请注意,如果该数据库尚不存在,则会创建该数据库。连接对象 db 有以下方法 -

先生。 方法与说明
1

光标():

返回使用此 Connection 的 Cursor 对象。

2

犯罪():

将任何挂起的事务显式提交到数据库。

3

回滚():

此可选方法会导致事务回滚到起始点。

4

关闭():

永久关闭与数据库的连接。

游标充当给定 SQL 查询的句柄,允许检索结果的一行或多行。使用以下语句从连接中获取游标对象以执行 SQL 查询 -

cur=db.cursor()

光标对象定义了以下方法 -

先生编号 方法与说明
1

执行()

执行字符串参数中的 SQL 查询。

2

执行许多()

使用元组列表中的一组参数执行 SQL 查询。

3

fetchone()

从查询结果集中获取下一行。

4

获取全部()

从查询结果集中获取所有剩余行。

5

调用过程()

调用存储过程。

6

关闭()

关闭光标对象。

以下代码在 test.db 中创建一个表:-

import sqlite3
db=sqlite3.connect('test.db')
cur =db.cursor()
cur.execute('''CREATE TABLE student (
StudentID INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT (20) NOT NULL,
age INTEGER,
marks REAL);''')
print ('table created successfully')
db.close()

数据库中所需的数据完整性是通过连接对象的commit()rollback()方法来实现的。SQL 查询字符串可能有不正确的 SQL 查询,可能会引发异常,应正确处理该异常。为此,execute() 语句被放置在 try 块中。如果成功,则使用 commit() 方法持久保存结果。如果查询失败,则使用 rollback() 方法撤消事务。

以下代码对 test.db 中的 Student 表执行 INSERT 查询。

import sqlite3
db=sqlite3.connect('test.db')
qry="insert into student (name, age, marks) values('Abbas', 20, 80);"
try:
   cur=db.cursor()
   cur.execute(qry)
   db.commit()
print ("record added successfully")
except:
   print ("error in query")
   db.rollback()
db.close()

如果您希望 INSERT 查询的值子句中的数据由用户输入动态提供,请使用 Python DB-API 中建议的参数替换。这 ?字符用作查询字符串中的占位符,并在execute() 方法中以元组的形式提供值。以下示例使用参数替换方法插入一条记录。姓名、年龄和分数作为输入。

import sqlite3
db=sqlite3.connect('test.db')
nm=input('enter name')
a=int(input('enter age'))
m=int(input('enter marks'))
qry="insert into student (name, age, marks) values(?,?,?);"
try:
   cur=db.cursor()
   cur.execute(qry, (nm,a,m))
   db.commit()
   print ("one record added successfully")
except:
   print("error in operation")
   db.rollback()
db.close()

sqlite3模块定义了executemany()方法,该方法能够一次添加多条记录。要添加的数据应在元组列表中给出,每个元组包含一条记录。列表对象是executemany() 方法的参数,以及查询字符串。然而,其他一些模块不支持executemany()方法。

UPDATE查询通常包含由 WHERE 子句指定的逻辑表达式。execute() 方法中的查询字符串应包含 UPDATE 查询语法要将 name='Anil' 的 'age' 值更新为 23,请按如下方式定义字符串:

qry="update student set age=23 where name='Anil';"

为了使更新过程更加动态,我们使用如上所述的参数替换方法。

import sqlite3
db=sqlite3.connect('test.db')
nm=input(‘enter name’)
a=int(input(‘enter age’))
qry="update student set age=? where name=?;"
try:
   cur=db.cursor()
   cur.execute(qry, (a, nm))
   db.commit()
   print("record updated successfully")
except:
   print("error in query")
   db.rollback()
db.close()

类似地,DELETE操作是通过使用具有SQL的DELETE查询语法的字符串调用execute()方法来执行的。顺便说一句,DELETE查询通常还包含WHERE子句。

import sqlite3
db=sqlite3.connect('test.db')
nm=input(‘enter name’)
qry="DELETE from student where name=?;"
try:
   cur=db.cursor()
   cur.execute(qry, (nm,))
   db.commit()
   print("record deleted successfully")
except:
   print("error in operation")
   db.rollback()
db.close()

对数据库表的重要操作之一是从中检索记录。为此,SQL 提供了SELECT查询。当将包含 SELECT 查询语法的字符串传递给execute() 方法时,将返回结果集对象。游标对象有两种重要的方法,可以使用它们从结果集中检索一条或多条记录。

fetchone()

从结果集中获取下一条可用记录。它是一个由所获取记录的每列值组成的元组。

获取全部()

以元组列表的形式获取所有剩余记录。每个元组对应一条记录并包含表中每一列的值。

以下示例列出了学生表中的所有记录

import sqlite3
db=sqlite3.connect('test.db')
37
sql="SELECT * from student;"
cur=db.cursor()
cur.execute(sql)
while True:
   record=cur.fetchone()
   if record==None:
      break
   print (record)
db.close()

如果您计划使用 MySQL 数据库而不是 SQLite 数据库,则需要如上所述安装PyMySQL模块。数据库连接过程中的所有步骤都是相同的,因为 MySQL 数据库安装在服务器上,所以 connect() 函数需要 URL 和登录凭据。

import pymysql
con=pymysql.connect('localhost', 'root', '***')

与 SQLite 唯一可能不同的是 MySQL 特定的数据类型。同样,通过安装 pyodbc 模块,任何 ODBC 兼容数据库都可以与 Python 一起使用。

Python 数据持久化 - SQLAlchemy

任何关系数据库都将数据保存在表中。表结构定义了属性的数据类型,这些属性基本上只是基本数据类型,映射到相应的Python内置数据类型。但是,Python 的用户定义对象无法持久存储到 SQL 表或从 SQL 表中检索。

这是 SQL 类型和面向对象编程语言(例如 Python)之间的差异。SQL 没有与其他数据类型(例如字典、元组、列表或任何用户定义的类)等效的数据类型。

如果必须将对象存储在关系数据库中,则在执行 INSERT 查询之前,应首先将其实例属性解构为 SQL 数据类型。另一方面,从 SQL 表检索的数据是主要类型。所需类型的 Python 对象必须通过在 Python 脚本中使用来构造。这就是对象关系映射器有用的地方。

对象关系映射器 (ORM)

对象关系映射器( ORM) 是类和 SQL 表之间的接口。将Python类映射到数据库中的某个表,从而自动进行对象和SQL类型之间的转换。

用Python代码编写的Students类映射到数据库中的Students表。因此,所有的CRUD操作都是通过调用类的相应方法来完成的。这消除了在 Python 脚本中执行硬编码 SQL 查询的需要。

因此,ORM 库充当原始 SQL 查询的抽象层,有助于快速应用程序开发。SQLAlchemy是一种流行的 Python 对象关系映射器。对模型对象状态的任何操作都与其数据库表中的相关行同步。

SQLALchemy 库包括ORM API和 SQL 表达式语言(SQLAlchemy 核心)。表达式语言直接执行关系数据库的原始构造。

ORM 是构建在 SQL 表达式语言之上的高级抽象使用模式。可以说ORM是表达语言的一种应用用法。我们将讨论 SQLAlchemy ORM API 并在其中使用 SQLite 数据库