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

ここで文字列サブクラスを実装することがどのように役立つかはわかりません。ペタバイト単位のデータを含むストリームを処理している場合、必要のないオブジェクトを作成したときはいつでも、ゲームに負けているように思えます。最優先事項は、できるだけ多くの入力を無視することです。

これを行う文字列のようなクラスを確実に構築できます。

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です。とにかく、文字列変換中に文字列全体がデコードされます。0len(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

答えは使用するエンコーディングの詳細に依存するという点で、質問は不完全です。

たとえば、文字列のリストをパスカル文字列としてエンコードし (つまり、固定サイズの整数としてエンコードされた文字列の長さを前に付けて)、リストから 100 番目の文字列を読みたいとすると、それぞれの文字列に対して seek() を進めることができます最初の 99 個の文字列が読み込まれ、その内容はまったく読み取られません。文字列が大きい場合、これによりパフォーマンスが向上します。

OTOH、文字列のリストを連結された 0 で終わるスターリングとしてエンコードする場合、100 番目の 0 までのすべてのバイトを読み取る必要があります。

また、いくつかの「フィールド」について話していますが、あなたの例はまったく異なって見えます。

于 2009-11-02T00:12:39.360 に答える
0

オーバーライドする必要があるメソッドは、新しい文字列型をどのように使用する予定かによって異なります。

ただし、str ベースの型は私には少し疑わしいように見えますが、str の実装を調べて、value設定している属性があることを確認しました__init__()か? を実行しdir(str)ても、 にそのような属性があるとは限りませんstr。これは、通常の str メソッドがデータに対してまったく動作しない場合です。それ以外の場合、サブクラス化の利点は何なのか、それがあなたが望む効果であるとは思えません。

とにかく、非常に具体的な要件がない限り、基本データ型をサブクラス化するのは少し奇妙です。遅延評価を行うには、str をサブクラス化するよりも文字列を含むクラスを作成し、そのクラスで動作するようにクライアント コードを記述する方がよいでしょう。その後、必要なジャスト イン タイム評価をさまざまな方法で自由に追加できます。記述子プロトコルを使用した例は、このプレゼンテーションで見つけることができます。Python のオブジェクト モデル(「class Jit(object)」を検索して、関連するセクション)

于 2009-11-01T11:06:46.397 に答える