写之前先写一个print的输出,一直知道print可以输出,没试过,但找到了资料就记录下,因为等下io会用到。
with open('abc.txt','w') as f:
2 print("file
","abc","fff",sep='#########
',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'x80x03]qx00(Kx01Kx02Kx03Kx04Kx05Kx06e.' [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]}, ["u6211u662fu5143u7956"]] [{'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"}, ["u6211u662fu5143u7956"]] [{'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"}, ["u6211u662fu5143u7956"]] [{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["u6211u662fu5143u7956"]] False False True [ { "b": "B", "a": { "b": "2", "a": "1" } }, { "a": [ 1, 2 ] }, { "c": "CD" }, [ "u6211u662fu5143u7956" ] ] [{"b": "B", "a": {"b": "2", "a": "1"}}, {"a": [1, 2]}, {"c": "CD"}, ["u6211u662fu5143u7956"]] 这个字数为97 [{"b":"B","a":{"b":"2","a":"1"}},{"a":[1,2]},{"c":"CD"},["u6211u662fu5143u7956"]] 这个字数为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