2017-09-08 4 views
0

J'essaie de faire une copie rapide d'une instance de classe. cPickle.loads(cPickle.dumps(),-1) fonctionne très bien, presque 5 fois plus vite que copy.deepcopy, mais je read that ujson is much faster than cPickle. Je ne pouvais pas faire travailler ujson avec un cours personnalisé, est-ce possible?est-il possible d'ujson.dumps() instance de classe python (deepcopy plus rapide)

exemple:

import cPickle as pickle 
import ujson 

class AClass(object): 
    def __init__(self): 
     print('init') 
     self.v = 10 
     self.z = [2,3,4] 
     self._zdict = dict(zip(self.z,self.z)) 

a = AClass() 
a 
#<__main__.AClass at 0x118b1d390> 


# does not work with ujson 
ua = ujson.dumps(a) 
au = ujson.loads(ua) 
au 
#{u'v': 10, u'z': [2, 3, 4]} 


# but works with pickle 
pa = pickle.dumps(a) 
ap = pickle.loads(pa) 
ap 
#<__main__.AClass at 0x117460190> 
+1

Non. Vous pouvez voir en regardant la sortie de 'ujson.dumps' (c'est juste un objet 'str') qu'il ne contient pas les informations nécessaires pour reconstruire l'objet source. C'est * juste * un encodeur JSON. Cela fait partie de la raison pour laquelle il est plus rapide que cPickle; ça n'a pas à faire autant. – chepner

+2

Je pense que vous devez développer votre propre protocole JSON. Il peut être facile de vider une instance de classe dans un objet JSON (en fait vous jetez le '__dict__'). Mais, il n'est pas facile de charger un objet JSON: comment différencier un 'dict' d'une instance de classe. Il n'y a pas de syntaxe JSON pour cela. –

Répondre

1

Une idée est de définir votre propre protocole, base du concept décrit pour pickle. Définir un __getstate__ et __setsatte__ instance dans votre classe:

class AClass(object): 
    def __init__(self, v, z): 
     self.v = v 
     self.z = z 
     self._zdict = dict(zip(self.z, self.z)) 

    def __repr__(self): 
     return repr({'v': self.v, 'z': self.z, '_zdict': self._zdict}) 

    def __getstate__(self): 
     return {'v': self.v, 'z': self.z} 

    def __setstate__(self, state): 
     self.__dict__.update(state) 
     self._zdict = dict(zip(self.z, self.z)) 

Ensuite, vous pouvez définir une save() et une fonction load() comme ceci:

import importlib 
import json 
import io 

def save(instance, dst_file): 
    data = { 
     'module': instance.__class__.__module__, 
     'class': instance.__class__.__name__, 
     'state': instance.__getstate__()} 
    json.dump(data, dst_file) 


def load(src_file): 
    obj = json.load(src_file) 
    module_name = obj['module'] 
    mod = importlib.import_module(module_name) 
    cls = getattr(mod, obj['class']) 
    instance = cls.__new__(cls) 
    instance.__setstate__(obj['state']) 
    return instance 

utilisation simple (en utilisant un StringIO ici au lieu d'un classique fichier):

a_class = AClass(10, [2, 3, 4]) 
my_file = io.StringIO() 
save(a_class, my_file) 

print(my_file.getvalue()) 
# -> {"module": "__main__", "class": "AClass", "state": {"v": 10, "z": [2, 3, 4]}} 

my_file = io.StringIO(my_file.getvalue()) 
instance = load(my_file) 

print(repr(instance)) 
# -> {'v': 10, 'z': [2, 3, 4], '_zdict': {2: 2, 3: 3, 4: 4}} 
2

ujson n'est pas sérialisation l'objet ; il s'agit simplement d'encoder son attribut dict en tant qu'objet JSON. Il n'y a pas assez d'informations pour reproduire l'objet original dans son intégralité; l'indication la plus évidente est que rien dans la sortie de ujson.dumps enregistre quelle classe a était une instance de.

La raison usjon est tellement plus rapide que cPickle est que cPickle doit faire beaucoup plus.

+0

donc, je suppose, 'cPickle' est mon meilleur pari – muon