9

次のようなスニペットがあります。

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メソッドを使用するには、snippet\class に何を変更すればよいでしょうか?
出来ますか?

4

3 に答える 3

26

別の方法が存在します。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 でのみ機能し、シリアライゼーション関連の属性とメタクラスでクラスが乱雑になることです。

于 2010-05-22T23:00:41.710 に答える
12

定義上、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)

ここでの利点は、クラスを (逆) シリアル化する方法を完全に制御できることです。つまり、ネットワーク経由でランダムに実行可能なコードを取得して実行することはありません。欠点は、クラスがどのように (デ) シリアル化されるかを完全に制御できることです。つまり、より多くの作業を行う必要があります。;-)

于 2010-04-13T07:33:36.333 に答える
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)をファイナライズします。

于 2016-02-23T14:39:03.707 に答える