2

我正在编写一个解析器,有很多文本要解码,但我的大多数用户只会关心所有数据中的几个字段。所以我只想在用户实际使用一些数据时进行解码。这是一个好方法吗?

class LazyString(str):
    def __init__(self, v) :
        self.value = v
    def __str__(self) :
        r = ""
        s = self.value
        for i in xrange(0, len(s), 2) :
            r += chr(int(s[i:i+2], 16))
        return r

def p_buffer(p):
    """buffer : HASH chars"""
    p[0] = LazyString(p[2])

这是我需要覆盖的唯一方法吗?

4

5 回答 5

2

我不确定在这里实现字符串子类有多大好处。在我看来,如果您正在处理包含 PB 级数据的流,那么每当您创建一个不需要的对象时,您就已经输掉了游戏。您的首要任务应该是尽可能多地忽略输入。

您当然可以构建一个类似字符串的类来执行此操作:

class mystr(str):
    def __init__(self, value):
        self.value = value
        self._decoded = None
    @property
    def decoded(self):
        if self._decoded == None:
            self._decoded = self.value.decode("hex")
            return self._decoded
    def __repr__(self):
        return self.decoded
    def __len__(self):
        return len(self.decoded)
    def __getitem__(self, i):
        return self.decoded.__getitem__(i)
    def __getslice__(self, i, j):
        return self.decoded.__getslice__(i, j)

等等。这样做的一个奇怪的事情是,如果你子类str化,你没有显式实现的每个方法都将在传递给构造函数的值上调用:

>>> s = mystr('a0a1a2')
>>> s
 ¡¢
>>> len(s)
3
>>> s.capitalize()
'A0a1a2'
于 2009-11-01T23:03:46.860 回答
1

我在您的代码中没有看到任何关于惰性评估的内容。您仅使用的事实xrange意味着将根据需要生成从0to的整数列表。len(s)无论如何,整个字符串r将在字符串转换期间被解码。

在 Python 中实现惰性序列的最佳方法是使用生成器。你可以尝试这样的事情:

def lazy(v):
    for i in xrange(0, len(v), 2):
        yield int(v[i:i+2], 16)

list(lazy("0a0a0f"))
Out: [10, 10, 15]
于 2009-11-01T00:58:49.497 回答
0

您正在做的事情已经内置:

s =  "i am a string!".encode('hex')
# what you do
r = ""
for i in xrange(0, len(s), 2) :
    r += chr(int(s[i:i+2], 16))
# but decoding is builtin
print r==s.decode('hex') # => True

如您所见,您的整个解码是s.decode('hex').

但是“懒惰”解码对我来说听起来像是过早的优化。您甚至需要千兆字节的数据才能注意到它。尝试分析,它.decode已经比旧代码快 50 倍。

也许你想要这样的东西:

class DB(object): # dunno what data it is ;)
    def __init__(self, data):
        self.data = data
        self.decoded = {} # maybe cache if the field data is long
    def __getitem__(self, name):
        try:
            return self.decoded[name]
        except KeyError:
            # this copies the fields data
            self.decoded[name] = ret = self.data[ self._get_field_slice( name ) ].decode('hex')
            return ret
    def _get_field_slice(self, name):
        # find out what part to decode, return the index in the data
        return slice( ... )

db = DB(encoded_data)    
print db["some_field"] # find out where the field is, get its data and decode it
于 2009-11-01T01:40:44.997 回答
0

您需要覆盖的方法实际上取决于计划如何使用您的新字符串类型。

但是,您基于 str 的类型对我来说有点可疑,您是否查看了 str 的实现以检查它是否具有value您在您的 中设置的属性__init__()?执行 adir(str)并不表示 上有任何此类属性str。在这种情况下,普通的 str 方法根本不会对您的数据进行操作,我怀疑这是您想要的效果,否则子类化的优势是什么。

无论如何,除非您有非常具体的要求,否则对基本数据类型进行子分类有点奇怪。对于您想要的惰性评估,您可能最好创建包含字符串的类而不是子类 str 并编写您的客户端代码以使用该类。然后,您可以通过多种方式自由地添加所需的即时评估,使用描述符协议的示例可以在此演示文稿中找到:Python 的对象模型(搜索“class Jit(object)”以获取相关的部分)

于 2009-11-01T11:06:46.397 回答
0

这个问题是不完整的,因为答案将取决于您使用的编码的细节。

比如说,如果你将一个字符串列表编码为帕斯卡字符串(即以字符串长度为前缀,编码为一个固定大小的整数),并说你想从列表中读取第 100 个字符串,你可以为每个字符串进行 seek()前 99 个字符串,根本不读取它们的内容。如果字符串很大,这将带来一些性能提升。

如果,OTOH,将字符串列表编码为连接的 0 终止符,则必须读取所有字节,直到第 100 个 0。

此外,您正在谈论一些“领域”,但您的示例看起来完全不同。

于 2009-11-02T00:12:39.360 回答