2010-04-13 14 views
6

इस तरह एक टुकड़ा होने:सुरक्षित_लोड का उपयोग कर PyYAML के साथ किसी ऑब्जेक्ट को deserialize कैसे करें?

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 किसी भी डेटा के साथ एक अविश्वसनीय स्रोत से प्राप्त कॉल करने के लिए नहीं है, तो, सुरक्षित_लोड विधि का उपयोग करने के लिए मुझे अपने स्निपेट \ कक्षा में क्या संशोधित करना चाहिए?
क्या यह संभव है?

उत्तर

9

ऐसा प्रतीत होता है कि परिभाषा के अनुसार सुरक्षित_लोड, आपको अपनी कक्षाओं को 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

एक और तरीका मौजूद है। पाययामल दस्तावेज़ों से:

एक अजगर वस्तु को सुरक्षित के रूप में चिह्नित किया जा सकता है और इस प्रकार 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 है; नुकसान यह है कि यह केवल सुरक्षित_लोड के साथ काम करता है और धारावाहिक से संबंधित विशेषताओं और मेटाक्लास के साथ आपकी कक्षा को अव्यवस्थित करता है।

+0

अच्छा समाधान। धन्यवाद – systempuntoout

+0

यह समाधान बहुत साफ है। नाइस !!! –

2

यदि आपके पास कई टैग हैं और उन सभी के लिए ऑब्जेक्ट्स बनाना नहीं चाहते हैं, या यदि आपको वास्तविक प्रकार के बारे में परवाह नहीं है, तो केवल डॉट किए गए एक्सेस के बारे में, आप निम्नलिखित कोड के साथ सभी अपरिभाषित टैग को पकड़ते हैं :

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 है: कि अपने बच्चों के निर्माण से अलग वस्तु instantiating के लिए अनुमति देता है। एक बार ऑब्जेक्ट मौजूद होने के बाद इसे किसी एंकर और बच्चों (या उनके बच्चों) के संदर्भ में संदर्भित किया जा सकता है। ऑब्जेक्ट बनाने के लिए वास्तविक तंत्र पहले इसे बनाता है, फिर इसे अंतिम रूप देने के लिए next(x) करता है।

संबंधित मुद्दे