Вопрос

Я пишу синтаксический анализатор, и там МНОГО текста для декодирования, но большинству моих пользователей будут интересны только несколько полей из всех данных.Поэтому я хочу выполнять декодирование только тогда, когда пользователь действительно использует некоторые данные.Хороший ли это способ сделать это?

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])

Это единственный метод, который мне нужно переопределить?

Это было полезно?

Решение

Я не уверен, насколько реализация подкласса string принесет здесь большую пользу.Мне кажется, что если вы обрабатываете поток, содержащий петабайты данных, всякий раз, когда вы создаете объект, который вам не нужен, вы уже проиграли игру.Вашим первым приоритетом должно быть игнорирование как можно большего количества входных данных.

Вы, конечно, могли бы создать string-подобный класс, который делал бы это:

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'

Другие советы

Я не вижу в вашем коде никаких указаний на отложенную оценку.Тот факт, что вы используете xrange означает только, что список целых чисел из 0 Для 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]

То, что вы делаете, уже встроено:

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

Методы, которые вам нужно переопределить, действительно зависят от того, как вы планируете использовать свой новый строковый тип.

Однако ваш тип на основе str выглядит для меня немного подозрительно, вы заглядывали в реализацию str, чтобы проверить, что она имеет value атрибут, который вы устанавливаете в своем __init__()?Выполняя dir(str) не указывает на наличие какого-либо такого атрибута на str.В этом случае обычные методы str вообще не будут работать с вашими данными, я сомневаюсь, что это тот эффект, которого вы хотите, иначе в чем было бы преимущество подклассирования.

Подклассирование базовых типов данных в любом случае немного странно, если только у вас нет очень специфических требований.Для отложенной оценки, которую вы хотите, вам, вероятно, лучше создать свой класс, содержащий строку, а не подклассировать str и написать свой клиентский код для работы с этим классом.Затем вы сможете добавить требуемую оценку точно в срок несколькими способами пример использования протокола descriptor можно найти в этой презентации: Объектная модель Python (найдите "класс Jit (object)", чтобы перейти к соответствующему разделу)

Вопрос является неполным, поскольку ответ будет зависеть от деталей используемой вами кодировки.

Скажем, если вы кодируете список строк как строки pascal (т.е.с префиксом длины строки, закодированной как целое число фиксированного размера), и скажем, вы хотите прочитать 100-ю строку из списка, вы можете переадресовать seek() для каждой из первых 99 строк и вообще не читать их содержимое.Это даст некоторый прирост производительности, если строки будут большими.

Если, OTOH, вы кодируете список строк как объединенные строки, заканчивающиеся 0, вам пришлось бы прочитать все байты до 100-го 0.

Кроме того, вы говорите о некоторых "полях", но ваш пример выглядит совершенно иначе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top