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


    写之前先写一个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

  • 相关阅读:
    page1
    CodeForces
    树、递归————二叉树的所有路径
    树(未完)
    树、递归、遍历————二叉搜索树的最近公共祖先
    树、递归————翻转二叉树
    树、递归————路径总和
    树、递归、广度优先搜索(BFS)————二叉树的最小深度
    树————平衡二叉树
    平衡二叉树AVL
  • 原文地址:https://www.cnblogs.com/sidianok/p/11892682.html
Copyright © 2020-2023  润新知