如何创建任意内存大小的对象?

时间:2015-04-27 11:08:37

标签: python-2.7

我正在编写一个哈希函数来创建一些给定大小的哈希值(例如20位)。

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

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

1 个答案:

答案 0 :(得分:1)

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

这里有一个基于pypi中的一个例子,用C语言实现了速度:

# uses https://pypi.python.org/pypi/bitarray
from bitarray import bitarray as BitArray

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 'length of hashes array: {:,} bits'.format(hashes.length())
    print ''
    print 'populate hashes array:'
    for i in xrange(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 xrange(len(hashes)):
        print ('  hashes[{}]: {:,} '
                '(0b{:0{}b})'.format(i, hashes[i], hashes[i], HW))

输出:

length of hashes array: 60 bits

populate hashes array:
  hashes[0] <- 1,017,914 (0b11111000100000111010)
  hashes[1] <- 75,689 (0b00010010011110101001)
  hashes[2] <- 750,954 (0b10110111010101101010)

contents of hashes array:
  hashes[0]: 1,017,914 (0b11111000100000111010)
  hashes[1]: 75,689 (0b00010010011110101001)
  hashes[2]: 750,954 (0b10110111010101101010)

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