io,pickle,json,一把梭哈,把这三个模块都讲了。

写之前先写一个print的输出,一直知道print可以输出,没试过,但找到了资料就记录下,因为等下io会用到。

with open('abc.txt','w') as f:
2     print("file\n","abc","fff",sep='#########\n',end='',file=f)
其结果:
将输出写到了文件abc.txt。
abc.txt的内容如下:
file
#########
abc#########
fff

先上io.StringIO,这个一个再内存中可以存入或者读取字符串的方式。

import io

output = io.StringIO()
output.write('This goes into the buffer')
print('==>And so does this 1', file=output)  # 将print的输出部分写入到内存对象中
output.seek(0)                           # 将读取位置移动到最前面
print('read', output.read())            # 非初始化写入的数据,read不能读取
print(output.getvalue())  # 取出该内存地址内数据
output.close()  # 关闭地址

input = io.StringIO('Inital value')        # 初始化对象
print('read====>   2', input.read())           # 读取数据
input.seek(0)
print(input.getvalue())                    # getvalue方式读取数据不影响seek定位
print('read====>     3', input.read())        # read读取到最后面
input.write('<hello')              # 后面追加数据。
print(input.read())           
print('=' * 10)
print(input.getvalue())

print(dir(output))
read This goes into the buffer==>And so does this 1

This goes into the buffer==>And so does this 1

read====>   2 Inital value
Inital value
read====>     3 Inital value

==========
Inital value<hello
['__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'getvalue', 'isatty', 'line_buffering', 'newlines', 'read', 'readable', 'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'writelines']

其实从该对象可以看出来,它好像 with open('xx') as f的f对象里面的属性。

相对与io.StringIO,还有io.BytesIO(),从字面上就可以看出来,该内存里面存的是字节码。

使用方法跟方式跟StringIO差不多。

oo = io.BytesIO(b'i love you')
print(oo.getvalue())
print(oo.read())
oo.seek(0)
print(oo.read().decode())     # 解码读取一下数据
oo.write(b'you love me')
print(oo.getvalue())

 

b'i love you'
b'i love you'
i love you
b'i love youyou love me'

 IO模块还是非常简单的,就是开辟了一块内存给你临时保存数据用。

pickle我查询了一些资料,还是非常强大的,而且书上跟网上的资料有些地方信息不一致。

概念:pickle模块实现了一个算法可以将一个任意的Python对象转换为一系列字节。这个过程也被称为串行化对象。可以传输或存储表示对象的字节流,然后再重构创建有相同性质的新对象。

从概念来看,就是可以把对象转换成字节流,便于传输或者保存,以后还可以读取出来。

先简单上一下最多使用的,pickle.dumps,puckle.dump,pickle.loads,pickle.load

import pickle
import pprint

date = [1, 2, 3, 4, 5, 6]
print('data is {}'.format(date))
date_string = pickle.dumps(date)
print('Pickle_date is {}'.format(date_string))

r_date = pickle.loads(date_string)
print(r_date)
print(r_date == date)
print(r_date is date)
data is [1, 2, 3, 4, 5, 6]
Pickle_date is b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04K\x05K\x06e.'
[1, 2, 3, 4, 5, 6]
True
False

 

通过上面的简单代码展示, pickle可以简单的通过字节码的形式保存并且读取一个对象,对象与原对象值相等,但地址不同。

 

pickle.dump可以像一个流写入多个对象,这里通过io.Bytesio来创建流。

 

import io
import pickle

class SimpleObject:

    def __init__(self, name):
        self.name = name
        self.name_backwards = name[::-1]


data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('preserve'))
data.append(SimpleObject('last'))

# 创建一个内存的字节流
out_s = io.BytesIO()

# 写入字节流数据
for o in data:
    print('{},{}正在被写入字节流out_s'.format(o.name,o.name_backwards))
    pickle.dump(o, out_s)


# 指针回到字节流头部
out_s.seek(0)

while True:
    try:
        o = pickle.load(out_s)
    except EOFError:
        break
    else:
        print('OUT :({}),({})'.format(o.name,o.name_backwards))

 

pickle,elkcip正在被写入字节流out_s
preserve,evreserp正在被写入字节流out_s
last,tsal正在被写入字节流out_s
OUT :(pickle),(elkcip)
OUT :(preserve),(evreserp)
OUT :(last),(tsal)

 从上面的列子中可以看到多次写入流当中,可以也可以通过循环从流当中读出,所以保存对个对象的时候还是非常方便的。

 

__getstate__与__setstate__主要是用来不可颜值的对象属性时使用,__getstate__方法可以返回一个对象,其中包含颜值对象的内部状态,表示状态的一种便利方式时使用字典。返回值为state

再pickle加载对象时,会从__setstate__的state参数中传入数据,开业通过__setstate__内部的一些函数返回数据实例。

由于对于这一块我了解不深,就不上实例。

 

了解了pickle,再来说一下json,看了Pthon标准库书中的介绍,有了重新的,认识,其实json的处理比pickle强大多了

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

网络传输中,更多的是用到了json的数据,json的类型是字符串形式,通过encode字节码就可以在网络中传输。

因为JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

JSON类型Python类型
{} dict
[] list
"string" str
1234.56 int或float
true/false True/False
null None

 

 

json.dumps使用中有点像repr但repr实在太强大了,它是python多态中,最强大的方法,什么对象对能使用该方法。

import json

data = [{'a': 'A'}, {'b': (1, 2,)}, ('我是元祖',)]

re = repr(data)       
js_1 = json.dumps(data, ensure_ascii=False)
js_2 = json.dumps(data)
print('repr is {}'.format(re))
print('jsondumps_1 is {}'.format(js_1))
print('jsondumps_2 is {}'.format(js_2))
print(json.loads(js_1))
print(json.loads(js_2))

 

repr is [{'a': 'A'}, {'b': (1, 2)}, ('我是元祖',)]
jsondumps_1 is [{"a": "A"}, {"b": [1, 2]}, ["我是元祖"]]
jsondumps_2 is [{"a": "A"}, {"b": [1, 2]}, ["\u6211\u662f\u5143\u7956"]]
[{'a': 'A'}, {'b': [1, 2]}, ['我是元祖']]
[{'a': 'A'}, {'b': [1, 2]}, ['我是元祖']]

 通过上面的列子可以看出,json和repr的一个小区别,json.dumps在序列化数据后,里面的元祖数据会变成列表数据。

json.dumps在默认情况下,对于非ascii字符生成的是相对应的字符编码,而非原始字符。

可以通过ensure_ascii=False显示中文编码,dumps没有影响。

import json

data = [{'b': 'B', 'a': {'b': '2', 'a': '1'}}, {'a': (1, 2,)}, {'c': 'CD'}, ('我是元祖',)]

re = repr(data)
js_1 = json.dumps(data, ensure_ascii=False)
js_2 = json.dumps(data)
print('repr is {}'.format(re))
print('jsondumps_1 is {}'.format(js_1))
print('jsondumps_2 is {}'.format(js_2))
print(json.loads(js_1))
print(json.loads(js_2))

js_sort = json.dumps(data, sort_keys=True)  # 通过sort_keys可以把内容里面嵌套的字典,按照keys排序进行写入
print(js_sort)
js_no_sort = json.dumps(data, sort_keys=False)
print(js_no_sort)
print(js_sort == js_no_sort)  # 这个是排序好的字符串对比,所以肯定不想等
print(js_no_sort == js_1)  # 所以正能字符串能容完全一致的才能相等
print(js_no_sort == js_2)

print()
print(json.dumps(data, indent=3))  # 类似与pprint漂亮打印,我个人认为3与4的数值够了。

# 最后还有一个参数separators 参数是一个元祖,默认为(', ',': ')逗号与分号后面有空格,
# 可以修改成没有空格的

js_3 = json.dumps(data, separators=(',', ':'))
print(js_2,'这个字数为{}'.format(len(js_2)))
print(js_3,'这个字数为{}'.format(len(js_3)))

 输出为

repr is [{'b': 'B', 'a': {'b': '2', 'a': '1'}}, {'a': (1, 2)}, {'c': 'CD'}, ('我是元祖',)]
jsondumps_1 is [{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["我是元祖"]]
jsondumps_2 is [{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["\u6211\u662f\u5143\u7956"]]
[{'b': 'B', 'a': {'b': '2', 'a': '1'}}, {'a': [1, 2]}, {'c': 'CD'}, ['我是元祖']]
[{'b': 'B', 'a': {'b': '2', 'a': '1'}}, {'a': [1, 2]}, {'c': 'CD'}, ['我是元祖']]
[{"a": {"a": "1", "b": "2"}, "b": "B"}, {"a": [1, 2]}, {"c": "CD"}, ["\u6211\u662f\u5143\u7956"]]
[{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["\u6211\u662f\u5143\u7956"]]
False
False
True

[
   {
      "b": "B",
      "a": {
         "b": "2",
         "a": "1"
      }
   },
   {
      "a": [
         1,
         2
      ]
   },
   {
      "c": "CD"
   },
   [
      "\u6211\u662f\u5143\u7956"
   ]
]
[{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["\u6211\u662f\u5143\u7956"]] 这个字数为97
[{"b":"B","a":{"b":"2","a":"1"}},{"a":[1,2]},{"c":"CD"},["\u6211\u662f\u5143\u7956"]] 这个字数为85

 

通过实例可以学习到一些dumps里面的参数,包括sort_keys,indent,separators,我的老师说过,在与前面的数据交互中建议separators设置为全出括号的数据。

最后还有一个skipkeys参数,由于json的序列号参数的字典keys必须为字符串类型,如果为另外类型会报错,所以通过skipkeys可以跳过这个非法的keys的对应的values。

n_data = [{(1,): 'ok', 'b': 'B'}, {'a': 'A'}]
print(json.dumps(n_data, skipkeys=True))
print(json.dumps(n_data))

 报错

e "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
TypeError: keys must be str, int, float, bool or None, not tuple

 加了以后输出

[{"b": "B"}, {"a": "A"}]

 

下面讲一个json保存对象的过程,其实json.dumps是不能序列化对象的,只不过需要特定的函数把对象转换成字典,然后进行序列化数据

一下代码来至python3标准库

首先我们创建一个类,用于实例化对象。

class MyObj:
    def __init__(self, s):
        self.s = s

    def __repr__(self):
        return '<MyObj({})>'.format(self.s)

然后,我们后面的代码先写一个将实例化的对象转换成字典的函数。

import json
import json_myobj

obj = json_myobj.MyObj('instance value goes here')

print('First attempt')

try:
    print(json.dumps(obj))
except TypeError as err:
    print('ERROR', err)


def convert_to_builtin_type(obj):
    print('default(', repr(obj), ')')
    '对象开始装换成字典'
    d = {
        # 获取实例类的名字
        '__class__': obj.__class__.__name__,
        # 获取实例模具的名字,其实就是去掉了.py文件名
        '__module__': obj.__module__
    }
    d.update(obj.__dict__)
    return d

print()
print('With default')

print('转换后的对象为:{!r}'.format(convert_to_builtin_type(obj)))
# 第一种方式
print(json.dumps(obj, default=convert_to_builtin_type))

# 第二种方式,比较傻瓜,直接转换成字典进行序列化保存。
print(json.dumps(convert_to_builtin_type(obj)))

 运行结果:

First attempt
ERROR Object of type MyObj is not JSON serializable

With default
default( <MyObj(instance value goes here)> )
转换后的对象为:{'__class__': 'MyObj', '__module__': 'json_myobj', 's': 'instance value goes here'}
default( <MyObj(instance value goes here)> )
{"__class__": "MyObj", "__module__": "json_myobj", "s": "instance value goes here"}
default( <MyObj(instance value goes here)> )
{"__class__": "MyObj", "__module__": "json_myobj", "s": "instance value goes here"}

最后一个将读取出来的参数变成实例,语法很风骚。

import json



def dict_to_object(d):
    if '__class__' in d:
        class_name = d.pop('__class__')
        module_name = d.pop('__module__')
        # 获取imp
        module = __import__(module_name)
        # print(module,查看导入对象模块的名称)
        print('MODULE:', module.__name__)
        # 或者对象里面具体的类
        class_ = getattr(module, class_name)
        print('CLASS:',class_)
        args = {
            key: value
            for key,value in d.items()
        }
        print('INSTANCE ARGS:', args)
        # 通过解包复制给类,进行实例化
        inst = class_(**args)
        return inst
    else:
        inst = d
    return inst

encoded_object = '''
{"__class__": "MyObj", "__module__": "json_myobj", "s": "instance value goes here"}
'''
myobj_instance = json.loads(
    encoded_object,
    object_hook=dict_to_object
)
print(myobj_instance)

 运行结果:

/Users/shijianzhong/Desktop/bit_coin/.venv/bin/python /Users/shijianzhong/Desktop/bit_coin/test_file/json_load_object.py
MODULE: json_myobj
CLASS: <class 'json_myobj.MyObj'>
INSTANCE ARGS: {'s': 'instance value goes here'}
<MyObj(instance value goes here)>

 

json.dump,json.load主要是针对文件流的操作,跟pickle的dump,load差不多,非常简单不上代码了。

 

最后还有json.JSONEncoder,json.JSONEecoder,由于时间原因就不研究了,Python标准库这么多内容,还是先把一些基础的用法先笔记下。

 

三个内容一篇随笔,写的我累死了。

 

 

两个链接供参考,学习

https://www.liaoxuefeng.com/wiki/1016959663602400/1017624706151424

 

https://www.cnblogs.com/cobbliu/archive/2012/09/04/2670178.html

 

 

posted @ 2019-11-19 21:50  就是想学习  阅读(368)  评论(0编辑  收藏  举报