【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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM