2010-04-13 3 views
6

:safe_load를 사용하여 PyYAML로 객체를 역 직렬화하는 방법은 무엇입니까? 이 같은 조각 갖는

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 메서드를 사용하려면 어떻게해야합니까?
가능합니까?

답변

9

safe_load는 정의에 따라 자신의 클래스를 deserialize 할 수없는 것처럼 보입니다. 당신이 안전 할 경우에, 나는 이런 식으로 뭔가를 할 거라고 :

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) 

여기 장점은 당신이 당신의 클래스 (비) 직렬화 방식을 절대 제어 할 수 있다는 것입니다. 즉, 네트워크를 통해 임의의 실행 코드를 가져 와서 실행하지 않아도됩니다. 단점은 클래스의 직렬화 방식을 절대적으로 제어 할 수 있다는 것입니다. 즉, 더 많은 일을해야한다는 뜻입니다. ;-)

+0

+1 맑음. JSON을 사용하여 덤프에도 __dict__을 보았습니다. – systempuntoout

+0

우수! 기본적으로 멤버 네임 스페이스를 덤핑하는 것 뿐이며이를 수행하는 가장 좋은 방법은 사전입니다. – Benson

16

또 다른 방법이 있습니다. PyYaml 문서에서 :

python 개체는 안전하다고 표시되어 yaml.safe_load에서 인식 할 수 있습니다. 이렇게하려면 yaml.YAMLObject [...]에서 파생시키고 클래스 속성 yaml_loader를 명시 적으로 yaml.SafeLoader로 설정합니다.

yaml_tag 속성을 설정해야 작동합니다.

YAMLObject는 개체를로드 가능한 상태로 만들기 위해 일부 메타 클래스 마법을 사용합니다. 이 작업을 수행하면 객체는 안전 로더에 의해서만로드 될 수 있고 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) 

이 하나의 장점은 할 prety 쉽게이다; 단점은 safe_load와 함께 작동하고 직렬화 관련 특성 및 메타 클래스로 클래스를 혼란시키는 것입니다.

+0

멋진 솔루션입니다. 감사합니다 – systempuntoout

+0

이 솔루션은 훨씬 청소기입니다. 좋은!!! –

2

태그가 많고 모든 태그를 생성하지 않으려는 경우 또는 반환 된 실제 유형에 대해 신경 쓰지 않는 경우 점선으로 표시된 액세스에 대해서만 다음 코드로 정의되지 않은 태그를 모두 잡습니다. : 아이의 창조와 별도로 오브젝트를 인스턴스화 수 있습니다 다음 my_construct_undefined가 중간에 yield을 가지고 왜 경우

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) 

당신이 궁금합니다. 객체가 존재하면 앵커가 있고 자식 (또는 자식)의 참조가있는 경우 참조 할 수 있습니다. 먼저 객체를 생성하는 실제 메커니즘이 객체를 생성 한 다음 next(x)을 호출하여 객체를 완성합니다.

관련 문제