Pregunta

Estoy escribiendo un programa de análisis, y hay un montón de texto para decodificar, pero la mayoría de mis usuarios sólo se preocupan por unos campos de todos los datos. Así que sólo quiero hacer la decodificación cuando un usuario utiliza realmente algunos de los datos. Es esta una buena manera de hacerlo?

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

Es el único método que necesito para anular?

¿Fue útil?

Solución

No estoy seguro de cómo implementar una subclase de cadena es de gran ventaja aquí. Me parece que si se está procesando una corriente que contiene petabytes de datos, siempre que se haya creado un objeto que no es necesario ya has perdido el juego. Su primera prioridad debe ser hacer caso omiso tanto de entrada como le sea posible.

Por supuesto que podría construir una clase similar a una cuerda que hizo esto:

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)

y así sucesivamente. Una cosa rara de hacer esto es que si subclase str, todos los métodos que no se implementan de forma explícita será llamado en el valor que se pasa al constructor:

>>> s = mystr('a0a1a2')
>>> s
 ¡¢
>>> len(s)
3
>>> s.capitalize()
'A0a1a2'

Otros consejos

No veo ningún tipo sobre la evaluación perezosa en su código. El hecho de que se utiliza xrange sólo significa que la lista de números enteros de 0 a len(s) se generará en la demanda. Todo el r cadena será decodificado durante la conversión de cadenas de todos modos.

La mejor manera de poner en práctica la secuencia perezosa en Python está utilizando generadores . Usted podría intentar algo como esto:

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]

Lo que está haciendo está construido en ya:

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

Como se puede ver toda su decodificación se s.decode('hex').

Pero decodificación "perezosa" suena como la optimización prematura a mí. Se necesitaría gigabytes de datos para siquiera notarlo. Trate de perfiles, la .decode es 50 veces más rápido que el código antiguo ya.

Tal vez usted quiere algo como esto:

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

Los métodos que necesita para anular realmente dependen de cómo están planeando usar nuevo tipo cadena.

Sin embargo, usted str tipo basado parece un poco sospechoso para mí, ¿has mirado en la implementación de str para comprobar que tiene el atributo value que se está configurando en su __init__()? La realización de una dir(str) no indica que existe tal atributo en str. Siendo este el caso, los métodos str normales no estarán operando en su dato en absoluto, no creo que ese es el efecto que desee lo contrario de lo que sería la ventaja de sub-classing.

subclasificar los tipos de datos base es un poco extraño de todas formas a menos que tenga necesidades muy específicas. Para la evaluación perezosa desea usted es probablemente mejor de la creación de su clase que contiene una cadena en lugar de sub-clasificar a str y escribir su código de cliente para trabajar con esa clase. A continuación, será libre de añadir la evaluación justo a tiempo que desee en un número de maneras un ejemplo utilizando el protocolo descriptor se puede encontrar en esta presentación: Python modelo de objetos (busque "Jit clase (objeto)" para llegar a la sección correspondiente)

La pregunta es incompleta, en la que la respuesta dependerá de los detalles de la codificación que utiliza.

Es decir, si se codifica una lista de cadenas como cadenas Pascal (es decir, el prefijo de longitud de serie codificado como un número entero de tamaño fijo), y dice que quiere leer la cadena número 100 de la lista, puede buscar () hacia adelante para cada uno de los primeros 99 cuerdas y no leer su contenido en absoluto. Esto le dará alguna ganancia de rendimiento si las cadenas son grandes.

Si, otoh, codificar una lista de cadenas como concatenados 0 terminados en stirngs, que tendría que leer todos los bytes hasta los 100 0.

Además, usted está hablando acerca de algunos "campos", pero su ejemplo se ve completamente diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top