Pergunta

Ter um trecho como este:

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 diz que não é seguro chamar yaml.carga com os dados recebidos a partir de uma fonte não confiável;então, o que devo modificar meus trecho\classe para usar safe_load método?
É possível?

Foi útil?

Solução

Parece que Safe_load, por definição, não permite que você desserialize suas próprias classes. Se você quiser que seja seguro, eu faria algo assim:

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)

A vantagem aqui é que você tem controle absoluto sobre como sua classe é (de) serializada. Isso significa que você não obterá código executável aleatório pela rede e executá -lo. A desvantagem é que você tem controle absoluto sobre como sua classe é (de) serializada. Isso significa que você precisa fazer muito mais trabalho. ;-)

Outras dicas

Outra maneira de existir.A partir do PyYaml docs:

Um objeto python podem ser marcados como seguros e, assim, ser reconhecido pelo yaml.safe_load.Para fazer isso, derivar-lo a partir de yaml.YAMLObject [...] e explicitamente defina sua propriedade de classe yaml_loader para yaml.SafeLoader.

Você também precisa definir o yaml_tag propriedade para fazê-lo funcionar.

YAMLObject faz algum metaclasse magia para fazer o objeto carregável.Observe que, se você fizer isso, os objetos só serão carregável pelo seguro carregador, não regular yaml.load().

Exemplo de trabalho:

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)

A vantagem desta é que é prety fácil de fazer;as desvantagens são que ele só funciona com safe_load e clutters sua classe com a serialização de atributos relacionados e metaclasse.

Se você tem muitas tags e não deseja criar objetos para todos eles, ou caso não se importe com o tipo real retornado, apenas sobre acesso pontilhado, você pega todas as tags indefinidas com o seguinte código:

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)

Caso você se pergunte por que o my_construct_undefined tem um yield No meio: isso permite instantar o objeto separadamente da criação de seus filhos. Uma vez que o objeto exista, ele pode ser referido, caso tenha uma âncora e das crianças (ou seus filhos) uma referência. O mecanismo real para criar o objeto primeiro o cria, depois faz um next(x) nele para finalizá -lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top