Wie ein Objekt mit PyYAML mit safe_load deserialisieren?
-
26-09-2019 - |
Frage
ein Snippet wie folgt zu haben:
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 sagt, dass es nicht sicher ist, zu nennen yaml.load mit beliebigen Daten von einer nicht vertrauenswürdigen Quelle empfangen; so, was soll ich zu meinen Schnipseln \ Klasse Verwendung ändern safe_load Methode?
Ist es möglich?
Lösung
Es scheint, dass safe_load per definitionem nicht lassen Sie Ihre eigenen Klassen deserialisieren. Wenn Sie es sicher sein wollen, ich so etwas tun würde:
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)
Der Vorteil hierbei ist, dass Sie absolute Kontrolle darüber haben, wie Sie Ihre Klasse (de) serialisiert. Das bedeutet, dass Sie nicht zufällig ausführbaren Code über das Netzwerk erhalten und ausführen. Der Nachteil ist, dass Sie absolute Kontrolle darüber haben, wie Sie Ihre Klasse (de) serialisiert. Das bedeutet Sie haben viel mehr Arbeit zu tun. ; -)
Andere Tipps
Eine andere Möglichkeit besteht. Aus der PyYaml docs:
Ein Python-Objekt kann als sicher markiert werden und damit von yaml.safe_load erkannt werden. Um dies zu tun, leiten sie aus yaml.YAMLObject [...] und ausdrücklich seine Klasse Eigenschaft yaml_loader auf yaml.SafeLoader gesetzt.
Sie können auch die yaml_tag Eigenschaft setzen müssen, damit es funktioniert.
YAMLObject hat einige metaclass Magie das Objekt belastbar zu machen. Beachten Sie, dass, wenn Sie dies tun, werden nur die Objekte, die von der sicheren Ladeprogramm, nicht mit regelmäßigen yaml.load ().
belastbar seinArbeits Beispiel:
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)
Der Vorteil dieser ist, dass es die prety einfach zu tun; Die Nachteile sind, dass es nur mit safe_load und clutters Ihre Klasse mit Serialisierung bezogene Attribute und metaclass funktioniert.
Wenn Sie viele Tags haben und nicht wollen, dass Objekte für alle von ihnen erstellen, oder falls Sie kümmern sich nicht um die tatsächliche Typ zurückgegeben, nur etwa gepunkteten Zugang, können Sie alle undefinierten Tags mit dem folgenden Code fangen:
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)
Falls Sie sich fragen, warum die my_construct_undefined
eine yield
in der Mitte hat: die von der Erstellung ihrer Kinder zum Instanziieren des Objekts getrennt werden können. Sobald das Objekt existieren kann es bezeichnet werden, falls es einen Anker hat und die Kinder (oder ihre Kinder) Referenz. Die tatsächliche mechanisme das Objekt erstellen zuerst schafft es, tut dann einen next(x)
auf, um es fertig zu stellen.