有一个这样的片段:
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 方法?
有可能吗?
答案 0 :(得分:21)
存在另一种方式。来自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)
这个的优势在于它很容易做到;缺点是它只适用于safe_load,并且使用与序列化相关的属性和元类来混淆你的类。
答案 1 :(得分:10)
根据定义,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)序列化的方式。这意味着你必须做更多的工作。 ; - )
答案 2 :(得分: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
:它允许将对象与其子项的创建分开实例化。一旦对象存在,就可以在具有锚点和子项(或其子项)作为引用的情况下引用它。创建对象的实际机制首先创建它,然后对其进行next(x)
以完成它。