Question

Je suis en train d'écrire un analyseur syntaxique, et il y a beaucoup de texte à décoder, mais la plupart de mes utilisateurs ne se soucient quelques champs de toutes les données. Donc, je veux seulement faire le décodage lorsqu'un utilisateur utilise en fait une partie des données. Est-ce une bonne façon de le faire?

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

est-ce que la seule méthode que je besoin de passer outre?

Était-ce utile?

La solution

Je ne suis pas sûr de savoir comment mettre en œuvre une sous-classe de la chaîne est de beaucoup d'avantages ici. Il me semble que si vous traitez un flux contenant pétaoctets de données, chaque fois que vous avez créé un objet que vous n'avez pas besoin de vous avez déjà perdu le jeu. Votre première priorité devrait être d'ignorer autant d'entrée que vous le pouvez.

Vous pouvez certainement construire une chaîne comme la classe qui a fait ceci:

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)

et ainsi de suite. Une chose étrange à faire est que si vous sous-classe str, chaque méthode que vous ne transposent explicitement sera appelée sur la valeur qui est passée au constructeur:

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

Autres conseils

Je ne vois aucune sorte sur l'évaluation paresseuse dans votre code. Le fait que vous utilisez xrange signifie seulement que la liste des entiers de 0 à len(s) sera généré à la demande. L'ensemble de la chaîne r sera décodé lors de la conversion de la chaîne de toute façon.

La meilleure façon de mettre en oeuvre la séquence dans le python paresseux utilise des générateurs . Vous pouvez essayer quelque chose comme ceci:

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]

Ce que vous faites est construit déjà:

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

Comme vous pouvez voir votre décodage entier est s.decode('hex').

Mais le décodage « paresseux » sonne comme l'optimisation trop tôt pour moi. Vous auriez besoin gigaoctets de données à l'avis même pas. Essayez le profilage, le .decode est 50 fois plus rapide que l'ancien code déjà.

Peut-être que vous voulez somthing comme ceci:

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

Les méthodes dont vous avez besoin pour passer outre dépend vraiment de la façon dont sont l'intention de vous utiliser un nouveau type de chaîne.

Cependant, vous str type à base ressemble un peu méfiant à moi, avez-vous regardé dans la mise en œuvre de str pour vérifier qu'il a l'attribut value que vous mettez dans votre __init__()? Réalisation d'une dir(str) ne signifie pas qu'il existe un tel attribut sur str. Cela étant les méthodes normales str ne fonctionneront pas sur vos données du tout, je doute que ce soit l'effet que vous voulez autrement ce serait l'avantage de sous-classes.

types de données de base sous-classage est un peu étrange de toute façon, sauf si vous avez des exigences très spécifiques. Pour l'évaluation paresseuse que vous voulez, vous êtes probablement mieux de créer votre classe qui contient une chaîne plutôt que sous-str et écrire classing votre code client pour travailler avec cette classe. Vous serez alors libre d'ajouter la juste évaluation du temps que vous voulez dans un certain nombre de façons, par exemple en utilisant le protocole descripteur se trouve dans cette présentation: Object Model Python (recherche de "Jit de classe (objet)" pour accéder à la section correspondante)

La question est incomplète dans la mesure où la réponse dépendra des détails de l'encodage que vous utilisez.

Dites, si vous encodez une liste de chaînes comme des chaînes pascals (c.-à-préfixées avec une longueur de chaîne codée comme un entier de taille fixe), et dites que vous voulez lire la 100ème chaîne dans la liste, vous pouvez demander () vers l'avant pour chacune des 99 premières chaînes et ne pas lire leur contenu du tout. Cela donnera un certain gain de performance si les chaînes sont grandes.

Si, OTOH, vous encodez une liste de chaînes comme concaténés 0 à terminaison stirngs, vous devez lire tous les octets jusqu'à ce que le 100ème 0.

En outre, vous parlez des « champs », mais votre exemple est complètement différente.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top