Вопрос

Наличие фрагмента, как это:

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. говорит, что это не безопасно звонить yaml.load. с любыми данными, полученными от ненадежного источника; Итак, что я должен изменить моему фрагменту класс использовать Safe_load. Метод?
Является ли это возможным?

Это было полезно?

Решение

Похоже, что Safe_load, по определению, не позволяет определить ваши собственные классы. Если вы хотите, чтобы это было безопасно, я бы сделал что-то подобное:

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)

Преимущество здесь заключается в том, что у вас есть абсолютный контроль над тем, как ваш класс (de) сериализован. Это означает, что вы не получите случайный исполняемый код через сеть и запустите его. Недостатком является то, что у вас есть абсолютный контроль над тем, как ваш класс (de) сериализован. Это означает, что вы должны сделать намного больше работы. ;-)

Другие советы

Еще один способ существует. Из документов Pyyaml:

Объект Python может быть помечен как безопасным и таким образом распознан yaml.safe_load. Для этого вытащите его от yaml.yamlobject [...] и явно установите свой свойство класса yaml_loader на yaml.safeloader.

Вы также должны установить свойство YAML_TAG, чтобы сделать его работать.

Yamlobject делает Metaclass Magic, чтобы заставить объект загружать. Обратите внимание, что если вы это сделаете, объекты будут загружаться только с помощью безопасного погрузчика, а не с обычными yaml.load ().

Рабочий пример:

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)

Преимущество этого заключается в том, что это тест на полугодие; Недостатки заключаются в том, что он работает только с Safe_load и закуривает ваш класс с атрибутами, связанными с сериализацией и метакласс.

Если у вас есть много тегов и не хочу создавать объекты для всех них, или если вам не волнует фактический тип возвращаемый, только о пунктирном доступе, вы ловите все неопределенные теги со следующим кодом:

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)

В случае, если вам интересно, почему my_construct_undefined имеет yield В середине: это позволяет создавать объект отдельно от создания своих детей. После того, как объект существует его можно упомянуть в случае, если у него есть якорь и дети (или их дети) ссылка. Фактическая механизма для создания объекта сначала создает его, то делает next(x) на нем, чтобы завершить его.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top