📜  面向对象的Python对象序列化

📅  最后修改于: 2021-01-04 04:47:35             🧑  作者: Mango


在数据存储的上下文中,序列化是将数据结构或对象状态转换为可以存储(例如,在文件或内存缓冲区中)或稍后传输和重构的格式的过程。

在序列化中,对象被转换为可以存储的格式,以便以后可以反序列化并从序列化的格式重新创建原始对象。

泡菜

酸洗是将Python对象层次结构转换为字节流(通常是人类不可读的)以写入文件的过程,这也称为序列化。取消拾取是相反的操作,由此字节流被转换回有效的Python对象层次结构。

泡菜是操作上最简单的存储对象的方法。 Python Pickle模块是一种面向对象的方法,可以直接以特殊的存储格式存储对象。

它能做什么?

  • Pickle可以非常容易地存储和复制字典和列表。
  • 存储对象属性,并将它们恢复到相同的状态。

什么泡菜不能做?

  • 它不保存对象代码。只有它的属性值。
  • 它不能存储文件句柄或连接套接字。

简而言之,腌制是一种将数据变量存储到文件中或从文件中检索数据变量的方法,变量可以是列表,类等。

要腌制某些东西,您必须-

  • 进口泡菜
  • 写一个变量到文件,类似
pickle.dump(mystring, outfile, protocol),

其中第3个参数协议是可选的要解开某些东西,您必须-

进口泡菜

将变量写入文件,类似于

myString = pickle.load(inputfile)

方法

Pickle界面提供了四种不同的方法。

  • dump() -dump()方法序列化到一个打开的文件(类似文件的对象)。

  • dumps() -序列化为字符串

  • load() -从类似打开的对象中反序列化。

  • loads() -从字符串反序列化。

根据上述步骤,以下是“酸洗”的示例。

酸洗

输出

My Cat pussy is White and has 4 legs
Would you like to see her pickled? Here she is!
b'\x80\x03c__main__\nCat\nq\x00)\x81q\x01}q\x02(X\x0e\x00\x00\x00number_of_legsq\x03K\x04X\x05\x00\x00\x00colorq\x04X\x05\x00\x00\x00Whiteq\x05ub.'

因此,在上面的示例中,我们创建了Cat类的实例,然后对其进行了腌制,将“ Cat”实例转换为简单的字节数组。

这样,我们可以轻松地将bytes数组存储在二进制文件或数据库字段中,并在以后的存储支持中将其恢复为原始格式。

同样,如果要创建一个带有腌制对象的文件,则可以使用dump()方法(而不是dumps *()*一个)传递一个打开的二进制文件,并且腌制结果将自动存储在该文件中。

[….]
binary_file = open(my_pickled_Pussy.bin', mode='wb')
my_pickled_Pussy = pickle.dump(Pussy, binary_file)
binary_file.close()

解开

接受二进制数组并将其转换为对象层次结构的过程称为解包。

通过使用pickle模块的load()函数完成取消腌制的过程,并从简单的字节数组返回完整的对象层次结构。

让我们在前面的示例中使用load函数。

不挑剔

输出

MeOw is black
Pussy is white

JSON格式

JSON(JavaScript Object Notation)已成为Python标准库的一部分,是一种轻量级的数据交换格式。人类易于阅读和书写。它很容易解析和生成。

由于其简单性,JSON是我们存储和交换数据的一种方式,这是通过JSON语法实现的,并在许多Web应用程序中使用。由于它是人类可读的格式,这可能是在数据传输中使用它的原因之一,此外,它在使用API时也很有效。

JSON格式的数据的示例如下-

{"EmployID": 40203, "Name": "Zack", "Age":54, "isEmployed": True}

Python使使用Json文件的工作变得简单。用于此目的的模块是JSON模块。该模块应包含在Python安装中(内置)。

因此,让我们看看如何将Python字典转换为JSON并将其写入文本文件。

JSON至Python

读取JSON意味着将JSON转换为Python值(对象)。 json库将JSON解析为Python的字典或列表。为此,我们使用loads()函数(从字符串加载),如下所示:

Json转Python

输出

Json转Python输出

以下是一个示例json文件,

data1.json
{"menu": {
   "id": "file",
   "value": "File",
   "popup": {
      "menuitem": [
         {"value": "New", "onclick": "CreateNewDoc()"},
         {"value": "Open", "onclick": "OpenDoc()"},
         {"value": "Close", "onclick": "CloseDoc()"}
      ]
   }
}}

上面的内容(Data1.json)看起来像常规字典。我们可以使用pickle来存储此文件,但是它的输出不是人类可读的形式。

JSON(Java脚本对象通知)是一种非常简单的格式,这是其流行的原因之一。现在,让我们通过下面的程序查看json输出。

Java脚本对象通知

输出

Java脚本对象通知输出

在上面,我们打开json文件(data1.json)进行读取,获取文件处理程序,然后传递给json.load并返回该对象。当我们尝试打印对象的输出时,它与json文件相同。尽管对象的类型是字典,但它作为Python对象出现。正如我们看到的泡菜一样,写入json很简单。在上面,我们加载json文件,添加另一个键值对并将其写回到相同的json文件。现在,如果我们看到data1.json,它看起来就不同。

为了使我们的输出看起来一样(人类可读的格式),请在程序的最后一行中添加几个参数,

json.dump(conf, fh, indent = 4, separators = (‘,’, ‘: ‘))

类似于pickle,我们可以打印带有转储的字符串,并带有负载。下面是一个例子

带转储的弦

YAML

对于所有编程语言,YAML可能是最人性化的数据序列化标准。

Python yaml模块称为pyaml

YAML是JSON的替代方法-

  • 易读代码-YAML是最易读的格式,因此,即使是其首页内容也可以在YAML中显示出来。

  • 紧凑的代码-在YAML中,我们使用空格缩进来表示结构而不是括号。

  • 关系数据的语法-对于内部引用,我们使用锚点(&)和别名(*)。

  • 它被广泛使用的领域之一是查看/编辑数据结构-例如配置文件,调试期间的转储和文档标题。

安装YAML

由于yaml不是内置模块,因此我们需要手动安装。在Windows机器上安装Yaml的最佳方法是通过pip。在Windows终端上运行以下命令以安装yaml,

pip install pyaml (Windows machine)
sudo pip install pyaml (*nix and Mac)

在运行上述命令时,屏幕将根据当前最新版本显示类似以下的内容。

Collecting pyaml
Using cached pyaml-17.12.1-py2.py3-none-any.whl
Collecting PyYAML (from pyaml)
Using cached PyYAML-3.12.tar.gz
Installing collected packages: PyYAML, pyaml
Running setup.py install for PyYAML ... done
Successfully installed PyYAML-3.12 pyaml-17.12.1

要进行测试,请转到Python shell并导入yaml模块,再导入yaml,如果未发现错误,则可以说安装成功。

安装pyaml之后,让我们看下面的代码,

script_yaml1.py

Yaml

在上面,我们创建了三个不同的数据结构,字典,列表和元组。在每个结构上,我们都执行yaml.dump。重要的是输出如何在屏幕上显示。

输出

Yaml输出

字典输出看起来很干净。核心价值。

空格分隔不同的对象。

列表用破折号(-)表示

元组首先用!! Python/ tuple,然后采用与列表相同的格式。

加载Yaml文件

假设我有一个yaml文件,其中包含

---
# An employee record
name: Raagvendra Joshi
job: Developer
skill: Oracle
employed: True
foods:
   - Apple
   - Orange
   - Strawberry
   - Mango
languages:
   Oracle: Elite
   power_builder: Elite
   Full Stack Developer: Lame
education:
   4 GCSEs
   3 A-Levels
   MCA in something called com

现在,让我们编写代码以通过yaml.load函数加载此yaml文件。下面是相同的代码。

Yaml加载功能

由于输出看起来不那么可读,因此我在最后使用json进行美化。比较我们得到的输出和我们拥有的实际yaml文件。

输出

Yaml3

软件开发最重要的方面之一是调试。在本节中,我们将介绍使用内置调试器或第三方调试器进行Python调试的不同方法。

PDB – Python调试器

PDB模块支持设置断点。断点是程序的有意暂停,您可以在其中获得有关程序状态的更多信息。

要设置断点,请插入行

pdb.set_trace()

pdb_example1.py
import pdb
x = 9
y = 7
pdb.set_trace()
total = x + y
pdb.set_trace()

我们在该程序中插入了一些断点。程序将在每个断点处暂停(pdb.set_trace())。要查看变量内容,只需键入变量名称。

c:\Python\Python361>Python pdb_example1.py
> c:\Python\Python361\pdb_example1.py(8)()
-> total = x + y
(Pdb) x
9
(Pdb) y
7
(Pdb) total
*** NameError: name 'total' is not defined
(Pdb)

按c或继续执行程序,直到下一个断点。

(Pdb) c
--Return--
> c:\Python\Python361\pdb_example1.py(8)()->None
-> total = x + y
(Pdb) total
16

最终,您将需要调试更大的程序-使用子例程的程序。有时,您要查找的问题将位于子例程中。考虑以下程序。

import pdb
def squar(x, y):
   out_squared = x^2 + y^2
   return out_squared
if __name__ == "__main__":
   #pdb.set_trace()
   print (squar(4, 5))

现在运行上面的程序,

c:\Python\Python361>Python pdb_example2.py
> c:\Python\Python361\pdb_example2.py(10)()
-> print (squar(4, 5))
(Pdb)

我们可以用吗?以获得帮助,但是箭头指示将要执行的行。在这一点上,按s到s进入该行很有帮助。

(Pdb) s
--Call--
>c:\Python\Python361\pdb_example2.py(3)squar()
-> def squar(x, y):

这是对函数的调用。如果您想要概述代码的位置,请尝试l-

(Pdb) l
1 import pdb
2
3 def squar(x, y):
4 -> out_squared = x^2 + y^2
5
6 return out_squared
7
8 if __name__ == "__main__":
9 pdb.set_trace()
10 print (squar(4, 5))
[EOF]
(Pdb)

您可以按n前进到下一行。此时,您在out_squared方法内,并且可以访问在函数.ie x和y中声明的变量。

(Pdb) x
4
(Pdb) y
5
(Pdb) x^2
6
(Pdb) y^2
7
(Pdb) x**2
16
(Pdb) y**2
25
(Pdb)

因此,我们可以看到^运算符不是我们想要的,而是需要使用**运算符进行平方。

这样,我们可以在函数/方法中调试程序。

记录中

自Python 2.3版以来,日志记录模块已成为Python标准库的一部分。由于它是一个内置模块,因此所有Python模块都可以参与日志记录,因此我们的应用程序日志可以包含您自己的消息以及来自第三方模块的消息。它提供了很多灵活性和功能。

记录的好处

  • 诊断日志记录-它记录与应用程序操作相关的事件。

  • 审核日志记录-它记录事件以进行业务分析。

消息以“严重性”和“最低”级别记录和记录

  • DEBUG(debug()) -用于开发的诊断消息。

  • INFO(info()) -标准的“进度”消息。

  • 警告(warning()) -检测到一个非严重问题。

  • ERROR(error()) -遇到错误,可能很严重。

  • 严重(critical()) -通常是致命错误(程序停止)。

让我们看下面的简单程序,

import logging

logging.basicConfig(level=logging.INFO)

logging.debug('this message will be ignored') # This will not print
logging.info('This should be logged') # it'll print
logging.warning('And this, too') # It'll print

上面我们在严重性级别上记录消息。首先,我们导入模块,调用basicConfig并设置日志记录级别。我们在上面设置的级别是INFO。然后,我们有三个不同的语句:调试语句,信息语句和警告语句。

logging1.py的输出

INFO:root:This should be logged
WARNING:root:And this, too

由于info语句位于debug语句下方,因此我们看不到调试消息。为了在Output终端中也获得debug语句,我们需要更改的只是basicConfig级别。

logging.basicConfig(level = logging.DEBUG)

在输出中,我们可以看到,

DEBUG:root:this message will be ignored
INFO:root:This should be logged
WARNING:root:And this, too

同样,默认行为表示如果我们未设置任何日志记录级别,则会发出警告。只需注释掉上面程序的第二行并运行代码即可。

#logging.basicConfig(level = logging.DEBUG)

输出

WARNING:root:And this, too

内置日志记录级别的Python实际上是整数。

>>> import logging
>>>
>>> logging.DEBUG
10
>>> logging.CRITICAL
50
>>> logging.WARNING
30
>>> logging.INFO
20
>>> logging.ERROR
40
>>>

我们还可以将日志消息保存到文件中。

logging.basicConfig(level = logging.DEBUG, filename = 'logging.log')

现在,所有日志消息都将转到当前工作目录中的文件(logging.log),而不是屏幕中。这是一种更好的方法,因为它可以让我们对收到的消息进行后期分析。

我们还可以通过日志消息设置日期戳。

logging.basicConfig(level=logging.DEBUG, format = '%(asctime)s %(levelname)s:%(message)s')

输出将得到类似的内容,

2018-03-08 19:30:00,066 DEBUG:this message will be ignored
2018-03-08 19:30:00,176 INFO:This should be logged
2018-03-08 19:30:00,201 WARNING:And this, too

标杆管理

基准测试或性能分析基本上是为了测试代码执行的速度以及瓶颈在哪里?这样做的主要原因是为了优化。

时间

Python带有一个称为timeit的内置模块。您可以使用它来计时小代码段。 timeit模块使用特定于平台的时间功能,因此您将获得最准确的计时。

因此,它使我们可以比较每个人使用的两次代码,然后优化脚本以提供更好的性能。

timeit模块具有命令行界面,但也可以导入。

有两种调用脚本的方法。首先使用脚本,运行以下代码并查看输出。

import timeit
print ( 'by index: ', timeit.timeit(stmt = "mydict['c']", setup = "mydict = {'a':5, 'b':10, 'c':15}", number = 1000000))
print ( 'by get: ', timeit.timeit(stmt = 'mydict.get("c")', setup = 'mydict = {"a":5, "b":10, "c":15}', number = 1000000))

输出

by index: 0.1809192126703489
by get: 0.6088525265034692

上面我们使用两种不同的方法。即通过下标访问字典的键值。我们执行一百万次语句,因为它对于非常小的数据执行得太快。现在,我们可以看到与get相比,索引访问要快得多。我们可以运行代码倍增时间,并且时间执行上会有细微的差异,以便更好地理解。

另一种方法是在命令行中运行上述测试。我们开始做吧,

c:\Python\Python361>Python -m timeit -n 1000000 -s "mydict = {'a': 5, 'b':10, 'c':15}" "mydict['c']"
1000000 loops, best of 3: 0.187 usec per loop

c:\Python\Python361>Python -m timeit -n 1000000 -s "mydict = {'a': 5, 'b':10, 'c':15}" "mydict.get('c')"
1000000 loops, best of 3: 0.659 usec per loop

以上输出可能会因系统硬件以及系统中当前正在运行的所有应用程序而异。

如果要调用函数,可以在下面使用timeit模块。由于我们可以在函数内部添加多个语句进行测试。

import timeit

def testme(this_dict, key):
   return this_dict[key]

print (timeit.timeit("testme(mydict, key)", setup = "from __main__ import testme; mydict = {'a':9, 'b':18, 'c':27}; key = 'c'", number = 1000000))

输出

0.7713474590139164