3

いくつかのYAMLオブジェクトをロードする際の小さな誤解だと思います。以下のクラスを定義しました。

私がやりたいのは、のオーバーライドされたloadConfig関数を使用していくつかのオブジェクトをロードすることですYAMLObjects。これらのいくつかは私の.yamlファイルからのものですが、他はYAMLファイルからロードされたオブジェクトから構築する必要があります。

たとえば、以下のクラスでは、「keep」という名前のメンバーオブジェクトをロードします。これは、リージョンに保持するいくつかのアイテムに名前を付ける文字列です。しかし、これもリストに解析して、リストをメンバーオブジェクトとして保存したいと思います。そして、ユーザーがYAMLでこのパラメーターの文字列バージョンとリストバージョンの両方を指定する必要がないようにします。

私の現在の回避策は、__getattr__内部の関数をオーバーライドし、表示されRegionても見つからない場合にデフォルトを作成するようにすることです。しかし、これは不格好で、オブジェクトを初期化するために必要なものよりも複雑です。

ここで私はどのような慣習を誤解していますか。loadConfigメソッドがYAMLにない追加のものを作成しないのはなぜですか?

import yaml, pdb

class Region(yaml.YAMLObject):
    yaml_tag = u'!Region'

    def __init__(self, name, keep, drop):
        self.name = name
        self.keep = keep
        self.drop = drop

        self.keep_list = self.keep.split("+")
        self.drop_list = self.drop.split("+")
        self.pattern = "+".join(self.keep_list) + "-" + "-".join(self.drop_list)
    ###

    def loadConfig(self, yamlConfig):
        yml = yaml.load_all(file(yamlConfig))
        for data in yml:

            # These get created fine
            self.name = data["name"]
            self.keep = data["keep"]
            self.drop = data["drop"]

            # These do not get created.
            self.keep_list = self.keep.split("+")
            self.drop_list = self.drop.split("+")
            self.pattern = "+".join(self.keep_list) + "-" + "-".join(self.drop_list)
    ###  
### End Region

if __name__ == "__main__":
    my_yaml = "/home/path/to/test.yaml"
    region_iterator = yaml.load_all(file(my_yaml))

    # Set a debug breakpoint to play with region_iterator and
    # confirm the extra stuff isn't created.
    pdb.set_trace()

そしてtest.yaml、これがすべてを実行して、私が何を意味するかを確認できるようにするためです。

 Regions:

   # Note: the string conventions below are for an
   # existing system. This is a shortened, representative
   # example.

   Market1:  
    !Region                 
        name: USAndGB
        keep: US+GB
        drop: !!null 

   Market2:
    !Region
        name: CanadaAndAustralia
        keep: CA+AU
        drop: !!null 

たとえば、これをIPythonシェルで実行し、ロードされたオブジェクトを探索すると、次のようになります。

In [57]: %run "/home/espears/testWorkspace/testRegions.py"
--Return--
> /home/espears/testWorkspace/testRegions.py(38)<module>()->None
-> pdb.set_trace()
(Pdb) region_iterator
<generator object load_all at 0x1139d820>
(Pdb) tmp = region_iterator.next()
(Pdb) tmp
{'Regions': {'Market2': <__main__.Region object at 0x1f858550>, 'Market1': <__main__.Region object at 0x11a91e50>}}
(Pdb) us = tmp['Regions']['Market1']
(Pdb) us
<__main__.Region object at 0x11a91e50>
(Pdb) us.name
'USAndGB'
(Pdb) us.keep
'US+GB'
(Pdb) us.keep_list
*** AttributeError: 'Region' object has no attribute 'keep_list'
4

1 に答える 1

4

基本的にストレージであるクラスのyamlを操作するのに役立つパターンは、ローダーにコンストラクターを使用させて、オブジェクトを通常の作成時と同じ方法で作成することです。あなたが正しくやろうとしていることを私が理解しているなら、この種の構造は役に立つかもしれません:

import inspect
import yaml
from collections import OrderedDict

class Serializable(yaml.YAMLObject):
    __metaclass__ = yaml.YAMLObjectMetaclass
    @property
    def _dict(self):
        dump_dict = OrderedDict()

        for var in inspect.getargspec(self.__init__).args[1:]:
            if getattr(self, var, None) is not None:
                item = getattr(self, var)
                if isinstance(item, np.ndarray) and item.ndim == 1:
                    item = list(item)
                dump_dict[var] = item

        return dump_dict

    @classmethod
    def to_yaml(cls, dumper, data):
        return ordered_dump(dumper, '!{0}'.format(data.__class__.__name__), 
                            data._dict)


    @classmethod
    def from_yaml(cls, loader, node):
        fields = loader.construct_mapping(node, deep=True)
        return cls(**fields)

def ordered_dump(dumper, tag, data):
    value = []
    node = yaml.nodes.MappingNode(tag, value)
    for key, item in data.iteritems():
        node_key = dumper.represent_data(key)
        node_value = dumper.represent_data(item)
        value.append((node_key, node_value))

    return node

次に、RegionクラスをSerializableから継承し、loadConfigのものを削除する必要があります。私が投稿したコードは、コンストラクターを調べてyamlファイルに保存するデータを確認し、yamlファイルをロードするときに、同じデータセットを使用してコンストラクターを呼び出します。そうすれば、コンストラクターでロジックを正しく取得する必要があり、yamlの読み込みで無料で取得できるはずです。

そのコードは私のプロジェクトの1つからリッピングされました。うまく機能しない場合は、事前にお詫び申し上げます。また、OrderedDictを使用して出力の順序を制御したかったため、必要以上に複雑になっています。私のordered_dump関数をdumper.represent_dictの呼び出しに置き換えることができます。

于 2013-02-19T14:34:25.960 に答える