【问题标题】:How to create objects of arbitrary memory size?如何创建任意内存大小的对象?
【发布时间】:2015-04-27 11:08:36
【问题描述】:

我正在编写一个散列函数来创建某个给定大小(例如 20 位)的散列。

我已经学会了如何以二进制形式将哈希写入文件(请参阅我的相关问题here),但现在我想使用最小内存分配在 Python (2.7) 中处理这些哈希。现在它们被键入为 int,因此它们每个被分配 24 个字节,这对于 20 位对象来说是巨大的。

如何创建任意大小的自定义 Python 对象(例如,在我的情况下为 3 个字节)?

【问题讨论】:

  • 你不能;无论如何,不​​在 Python 级别。
  • 如果您想对内存进行这种低级控制,Python 是错误的语言。它只是不是为这种用例而设计的。

标签: python-2.7


【解决方案1】:

您可以通过将每个对象的位打包到位(或布尔)值的打包数组中来做您想做的事情。有许多现有的 Python bitarray 扩展模块可用。用一个实现更高级别的“固定位宽整数值数组”是一个相对简单的过程。

这是一个基于 pypi 中的示例,该示例在 C 中实现以提高速度。您还可以从 here 下载由 Christoph Gohlke 创建的非官方预构建 Windows 版本。

更新 — 现在适用于 Python 2.7 和 3.x。

from __future__ import print_function
# uses https://pypi.python.org/pypi/bitarray
from bitarray import bitarray as BitArray
try:
    from functools import reduce  # Python 3.
except:
    pass


class PackedIntArray(object):
    """ Packed array of unsigned fixed-bit-width integer values. """
    def __init__(self, array_size, item_bit_width, initializer=None):
        self.array_size = array_size
        self.item_bit_width = item_bit_width
        self.bitarray = BitArray(array_size * item_bit_width)
        if initializer is not None:
            try:
                iter(initializer)
            except TypeError:  # not iterable
                self.bitarray.setall(initializer) # set all to bool(initializer)
            else:
                for i in xrange(array_size):
                    self[i] = initializer[i]  # must be same length as array

    def __getitem__(self, index):
        offset = index * self.item_bit_width
        bits = self.bitarray[offset: offset+self.item_bit_width]
        return reduce(lambda x, y: (x << 1) | y, bits, 0)

    def __setitem__(self, index, value):
        bits = BitArray('{:0{}b}'.format(value, self.item_bit_width))
        offset = index * self.item_bit_width
        self.bitarray[offset: offset+self.item_bit_width] = bits

    def __len__(self):
        """ Return the number of items stored in the packed array.. """
        return self.array_size

    def length(self):
        """ Return the number of bits stored in the bitarray.. """
        return self.bitarray.length()

    def __repr__(self):
        return('PackedIntArray({}, {}, ('.format(self.array_size,
                                                    self.item_bit_width) +
               ', '.join((str(self[i]) for i in xrange(self.array_size))) +
               '))')


if __name__ == '__main__':
    from random import randrange

    # hash function configuration
    BW = 8, 8, 4  # bit widths of each integer
    HW = sum(BW)  # total hash bit width

    def myhash(a, b, c):
        return (((((a & (2**BW[0]-1)) << BW[1]) |
                    b & (2**BW[1]-1)) << BW[2]) |
                    c & (2**BW[2]-1))

    hashes = PackedIntArray(3, HW)

    print('hash bit width: {}'.format(HW))
    print('length of hashes array: {:,} bits'.format(hashes.length()))
    print()
    print('populate hashes array:')
    for i in range(len(hashes)):
        hashed = myhash(*(randrange(2**bit_width) for bit_width in BW))
        print('  hashes[{}] <- {:,} (0b{:0{}b})'.format(i, hashed, hashed, HW))
        hashes[i] = hashed
    print()
    print('contents of hashes array:')
    for i in range(len(hashes)):
        print(('  hashes[{}]: {:,} '
                '(0b{:0{}b})'.format(i, hashes[i], hashes[i], HW)))

样本输出:

hash bit width: 20
length of hashes array: 60 bits

populate hashes array:
  hashes[0] <- 297,035 (0b01001000100001001011)
  hashes[1] <- 749,558 (0b10110110111111110110)
  hashes[2] <- 690,468 (0b10101000100100100100)

contents of hashes array:
  hashes[0]: 297,035 (0b01001000100001001011)
  hashes[1]: 749,558 (0b10110110111111110110)
  hashes[2]: 690,468 (0b10101000100100100100)

注意:bitarray.bitarray 对象也有向文件写入和读取其位的方法。这些也可用于提供与上述PackedIntArray 类类似的功能。

【讨论】:

  • 太好了,谢谢。一个细节:我猜 myhash 调用的最后一个参数应该是 randrange(16)。
  • 从技术上讲,是的,它应该是randrange(16),但是传递给myhash() 的第三个值被屏蔽为4 位,所以它不会引起明显的问题。无论如何都修复了它并优化了myhash()函数。
猜你喜欢
  • 2011-01-04
  • 2021-09-15
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2020-03-20
  • 2016-09-17
相关资源
最近更新 更多