zoukankan      html  css  js  c++  java
  • 【Python技巧系列】 Python中key-value格式数据存储方案

    key-value格式的存储的应用场景很多,通用的描述是『输入一个唯一标识的input,返回(查找)一个对应的output』。Python中字典(dictionary)就是一个内置的解决方案 - Python的字典本质上是一个哈希表,功能可对应Java的HashMap,但据说被尽可能地优化过(没有研究过细节,不随意展开),因此输入key的查询速度可以说是Python本身能达到的极致了。

    但是,并不是每个场景都是以查询速度为第一条件的。Python字典在建立的过程中同时也要建立一个C long型的哈希表(以及其他?),因此会额外占据很多空间。若是需要在内存中保持一个很大的key-value数据结构,并可以牺牲查询速度的话,也可以用其他方案替代。

    这篇整理一下Python中各种常用的key-value方案以及适用场景。

    Python自带字典(dictionary)

    • 优点:方便简洁,查询速度No.1
    • 缺点:占用内存空间。
    • 适用场景:内存足够。

    Pandas的Series / DataFrame

    这里我们主要关心的是,Series / DataFrame的索引中,用户自定义索引和内部建立的数值型索引的映射是怎么实现的?(重点 - 是字典吗?答案:是。)

    拿Series来举例:

    class Series(base.IndexOpsMixin, strings.StringAccessorMixin,
             generic.NDFrame,):
    
        def __init__(self, data=None, index=None, dtype=None, name=None,
                 copy=False, fastpath=False):
            ...
            self._set_axis(0, index, fastpath=True)
    
        def _set_axis(self, axis, labels, fastpath=False):
            ...
            self._data.set_axis(axis, labels)
            ...
    

    其中._datageneric.NDFrame初始化设置的对象属性值:

    class NDFrame(PandasObject):
            def __init__(self, data, axes=None, copy=False, dtype=None,
                 fastpath=False):
                 ...
                 object.__setattr__(self, '_data', data)
                 ...
    

    因此,我们追溯到.core.generic.NDFrames中定义的set_axis方法:

    def set_axis(self, axis, labels):
        """ public verson of axis assignment """
        setattr(self, self._get_axis_name(axis), labels)
    

    又追溯到同类中的_get_axis_name方法:

    def _get_axis_name(self, axis):
        axis = self._AXIS_ALIASES.get(axis, axis)
        if isinstance(axis, string_types):
            if axis in self._AXIS_NUMBERS:
                return axis
        else:
            try:
                return self._AXIS_NAMES[axis]
            except:
                pass
        raise ValueError('No axis named {0} for object type {1}'
                         .format(axis, type(self)))
    

    其中用到的._AXIS_ALIASES_AXIS_NUMBERS_AXIS_NAMES又追溯到了当前类的_setup_axes方法:

    @classmethod
    def _setup_axes(cls, axes, info_axis=None, stat_axis=None, aliases=None,
                    slicers=None, axes_are_reversed=False, build_axes=True,
                    ns=None):
    
        cls._AXIS_ORDERS = axes
        cls._AXIS_NUMBERS = dict((a, i) for i, a in enumerate(axes))
        cls._AXIS_LEN = len(axes)
        cls._AXIS_ALIASES = aliases or dict()
        cls._AXIS_IALIASES = dict((v, k) for k, v in cls._AXIS_ALIASES.items())
        cls._AXIS_NAMES = dict(enumerate(axes))
        cls._AXIS_SLICEMAP = slicers or None
        cls._AXIS_REVERSED = axes_are_reversed
    

    这个函数在series.py这个文件中是在class series外使用的,也就是一import就直接被执行,为以上的几个属性进行赋值(初始化?):

    Series._setup_axes(['index'], info_axis=0, stat_axis=0, aliases={'rows': 0})
    

    因此我们可以看到,axes,或者说axisindex的alias别名和实际使用用来查找的内部使用的index序号是用字典来映射的。

    也就是说,如果我们仅仅要用Series来存储一个key-value的数据结构,在存储上是和字典一个级别的。

    • 优点:数据分析功能多样。
    • 缺点:同字典。
    • 适用场景:内存足够,并且需要进行数据分析的活动。

    Python SQLite API

    • 优点:可选择在硬盘上存储。
    • 缺点:同一时间只能被一个连接访问修改,其他连接被加锁。
    • 适用场景:比较通用。不介意密集I/O操作,不介意查询速度。

    列表(list), 元组(tuple)

    元组是定长数组,列表是不定长数组。元组在存储空间上比列表节省16byte,估计是一个指针空位(?)

    • 优点:简洁快速。
    • 缺点:太过简陋。
    • 适用场景:key可以被序列化,key可以被一个公式映射成唯一的index,因此能够直接用key得知index。
  • 相关阅读:
    dockerfile 踩坑记录
    Windows安装配置xampp
    docker 容器中设置 mysql lampp php软链接
    linux 软件连接 创建/查看/删除
    mysql 远程连接权限
    linux设置静态获取ip
    android 自定义控件中获取属性的三种方式(转)
    android 自定义组件-带图片的textView
    CodeIgniter 3之Session类库(3)(转)
    CodeIgniter 3之Session类库(2)(转)
  • 原文地址:https://www.cnblogs.com/manqing/p/6657097.html
Copyright © 2011-2022 走看看