Question

Avoir un extrait comme ceci:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

Yaml docs dit que ce n'est pas sûr d'appeler yaml.load avec toutes les données reçues à partir d'une source non fiable; donc, que dois-je modifier mon extrait \ classe à utiliser safe_load méthode
Est-il possible?

Était-ce utile?

La solution

Il semble que safe_load, par définition, ne vous permet pas désérialiser vos propres classes. Si vous voulez qu'il soit sûr, je ferais quelque chose comme ceci:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

    def yaml(self):
       return yaml.dump(self.__dict__)

    @staticmethod
    def load(data):
       values = yaml.safe_load(data)
       return User(values["name"], values["surname"])

user = User('spam', 'eggs')
serialized_user = user.yaml()
print "serialized_user:  %s" % serialized_user.strip()

#Network
deserialized_user = User.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

L'avantage ici est que vous avez un contrôle absolu sur la façon dont votre classe est (de) sérialisé. Cela signifie que vous n'obtenir un code exécutable au hasard sur le réseau et l'exécuter. L'inconvénient est que vous avez un contrôle absolu sur la façon dont votre classe est (de) sérialisé. Cela signifie que vous devez faire beaucoup plus de travail. ; -)

Autres conseils

Une autre façon existe. Des PyYAML docs:

  

Un objet python peut être marqué comme sûr et ainsi être reconnu par yaml.safe_load. Pour ce faire, dériver de yaml.YAMLObject [...] et définir explicitement sa propriété de classe yaml_loader à yaml.SafeLoader.

Vous devez également définir la propriété yaml_tag pour le faire fonctionner.

YAMLObject fait un peu de magie métaclasse pour faire le chargeable objet. Notez que si vous faites cela, les objets ne seront chargeable par le chargeur sûr, pas avec yaml.load régulière ().

Exemple de travail:

import yaml

class User(yaml.YAMLObject):
    yaml_loader = yaml.SafeLoader
    yaml_tag = u'!User'

    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)

#Network

deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

L'avantage de celui-ci est qu'il est prety facile à faire; les inconvénients sont que cela fonctionne uniquement avec safe_load et votre classe avec encombre les attributs liés sérialisation et métaclasse.

Si vous avez beaucoup de balises et ne veulent pas créer des objets pour tous, ou si vous ne se soucient pas du type réel est revenu, seulement un accès en pointillé, vous attrapez tous les tags non définis avec le code suivant:

import yaml

class Blob(object):
    def update(self, kw):
        for k in kw:
            setattr(self, k, kw[k])

from yaml.constructor import SafeConstructor

def my_construct_undefined(self, node):
    data = Blob()
    yield data
    value = self.construct_mapping(node)
    data.update(value)

SafeConstructor.add_constructor(None, my_construct_undefined)


class User(object):
    def __init__(self, name, surname):
        self.name= name
        self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

Dans le cas où vous vous demandez pourquoi le my_construct_undefined a un yield au milieu: qui permet d'instancier l'objet séparément de la création de ses enfants. Une fois que l'objet existe, il peut être appelé dans le cas où il a un point d'ancrage et des enfants (ou leurs enfants) une référence. Le mechanisme réelle pour créer d'abord l'objet crée, fait alors un next(x) sur elle pour le finaliser.

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