TL; DR; Passer au fond de cette réponse pour le code de travail
Je suis sûr que certaines personnes détestent pickle
, il peut certainement donner quelques maux de tête lorsque le code refactoring (lorsque les classes d'objets marinées se déplacent à différents fichiers). Mais le plus gros problème est que le pickle n'est pas sûr, juste un YAML est dans la façon dont vous l'avez utilisé.
Il est pour intéressant de noter que vous ne pouvez pas décaper le plus lisible protocol level 0 (la valeur par défaut en Python 3 est la version du protocole 3):
pickle.dump (rngdct, f, protocole = 0) sera jeter:
TypeError: a class that defines slots without defining getstate cannot be pickled
en effet, le module/classe est un peu minimaliste, ce qui montre aussi (ou plutôt ne fonctionne pas) RangeDict
si vous essayez de le faire:
print(rngdict)
qui vient imprimer {}
Vous avez probablement utilisé la routine PyYAML dump()
(et son correspondant, peu sûr, load()
). Et bien que cela puisse vider des classes Python génériques, vous devez réaliser que cela a été implémenté avant ou à peu près en même temps que Python 3.0. (et le support de Python 3 a été implémenté plus tard). Et bien qu'il n'y ait aucune raison qu'un analyseur YAML puisse vider et charger les informations exactes que pickle
fait, il ne se connecte pas dans les routines de support pickle
(bien qu'il pourrait) et certainement pas dans les informations pour les protocoles de décapage spécifiques Python 3.
De toute façon, sans representer spécifique (et constructeur) pour RangeDict
objets, en utilisant YAML ne fait pas vraiment de sens: elle facilite le chargement potentiellement dangereux et votre YAML comprennent tous les détails sordides qui font l'objet efficace .Si vous faites yaml.dump()
:
!!python/object:rangedict.RangeDict
_root: &id001 !!python/object/new:rangedict.Node
state: !!python/tuple
- null
- color: 0
left: null
parent: null
r: !!python/tuple [1, 9]
right: !!python/object/new:rangedict.Node
state: !!python/tuple
- null
- color: 1
left: null
parent: *id001
r: !!python/tuple [10, 19]
right: null
value: {Series: '1', Type: B}
value: {Series: '1', Type: A}
Lorsque l'OMI une représentation lisible en YAML serait:
!rangedict
[1, 9]:
Type: A
Series: '1'
[10, 19]:
Type: B
Series: '1'
En raison des séquences utilisées en tant que touches, cela ne peut pas être chargé par PyYAML sans modifications majeures à la analyseur Mais heureusement, ces modifications ont été incorporées dans ruamel.yaml
(disclaimer: je suis l'auteur de ce paquet), de sorte que « tous » que vous devez faire est de sous-classe RangeDict
de fournir des méthodes representer approprié et constructeur (classe):
import io
import ruamel.yaml
from rangedict import RangeDict
class MyRangeDict(RangeDict):
yaml_tag = u'!rangedict'
def _walk(self, cur):
# walk tree left -> parent -> right
if cur.left:
for x in self._walk(cur.left):
yield x
yield cur.r
if cur.right:
for x in self._walk(cur.right):
yield x
@classmethod
def to_yaml(cls, representer, node):
d = ruamel.yaml.comments.CommentedMap()
for x in node._walk(node._root):
d[ruamel.yaml.comments.CommentedKeySeq(x)] = node[x[0]]
return representer.represent_mapping(cls.yaml_tag, d)
@classmethod
def from_yaml(cls, constructor, node):
d = cls()
for x, y in node.value:
x = constructor.construct_object(x, deep=True)
y = constructor.construct_object(y, deep=True)
d[x] = y
return d
rngdct = MyRangeDict()
rngdct[(1, 9)] = \
{"Type": "A", "Series": "1"}
rngdct[(10, 19)] = \
{"Type": "B", "Series": "1"}
yaml = ruamel.yaml.YAML()
yaml.register_class(MyRangeDict) # tell the yaml instance about this class
buf = io.StringIO()
yaml.dump(rngdct, buf)
data = yaml.load(buf.getvalue())
# test for round-trip equivalence:
for x in data._walk(data._root):
for y in range(x[0], x[1]+1):
assert data[y]['Type'] == rngdct[y]['Type']
assert data[y]['Series'] == rngdct[y]['Series']
Le buf.getvalue()
est exactement la représentation lisible montrée auparavant.
Si vous devez traiter le dumping RangeDict
lui-même (à savoir ne peut pas sous-classe parce que vous utilisez une bibliothèque qui a RangeDict
hardcoded), vous pouvez ajouter l'attribut et les méthodes de MyRangeDict
directement RangeDict
par greffage/monkeypatching.
Je pense que 'NSStock' était une faute de frappe, sinon ajoutez s'il vous plaît sa définition à votre exemple. – Anthon
C'est vrai! Désolé pour cela, j'ai renommé les variables, mais j'ai oublié celui-ci. Merci pour la remarque! @Anthon –