我正在编写一个解析器,并且有很多文本需要解码,但我的大多数用户只关心所有数据中的几个字段。所以我只想在用户实际使用某些数据时进行解码。这是一个很好的方法吗?
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])
这是我需要覆盖的唯一方法吗?
答案 0 :(得分: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'
答案 1 :(得分:1)
我在代码中看不到任何关于延迟评估的内容。您仅使用xrange
这一事实意味着将根据需要生成从0
到len(s)
的整数列表。无论如何,整个字符串r
将在字符串转换期间被解码。
在Python中实现延迟序列的最佳方法是使用generators。你可以尝试这样的事情:
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]
答案 2 :(得分: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
答案 3 :(得分:0)
您需要覆盖的方法实际上取决于计划如何使用新的字符串类型。
但是你基于str的类型对我来说有点怀疑,你是否考虑过str的实现来检查它是否具有你在value
中设置的__init__()
属性?执行dir(str)
并不表示str
上存在任何此类属性。在这种情况下,普通的str方法根本不会对你的数据进行操作,我怀疑这是你想要的效果,否则会有什么优势。
除非您有非常具体的要求,否则无论如何,子类基础数据类型都有点奇怪。对于你想要的懒惰评估,你可能更擅长创建包含字符串而不是子类化str的类,并编写客户端代码以使用该类。然后,您可以通过多种方式自由添加您想要的即时评估,在此演示文稿中可以找到使用描述符协议的示例:Python's Object Model(搜索“class Jit(object)”以获取相关部分)
答案 4 :(得分:0)
问题不完整,答案取决于您使用的编码细节。
比方说,如果你将一个字符串列表编码为pascal字符串(即以字符串长度编码为固定大小的整数),并且你想要从列表中读取第100个字符串,你可以寻求()转发前99个字符串中的每一个都没有读取它们的内容。如果字符串很大,这将获得一些性能提升。
如果,OTOH,你将一个字符串列表编码为连接的0终止的stirngs,你必须读取所有字节,直到第100个。
另外,你说的是一些“字段”,但你的例子看起来完全不同。