2017-02-15 10 views
2

PyYAMLの読みやすさが気に入っており、これをいくつかのオープンソースプロジェクトで使いたいと思っています。私はJSONの代替として取り組んでいます。PyYAMLとコンポジション、属性エラー

しかし、私は構成を使ってオブジェクトを構成する方法を正確に理解するのに苦労しています。私はこの質問を開いた:PyYAML - how to deal with compositonとそれは情報を読むことの面ではなく、完全なプログラムのコンテキストで動作するように見えた。

import yaml 
import data 

class DungeonObject(yaml.YAMLObject): 
    yaml_tag = u'!DungeonObject' 
    def __init__(self, x, y, char, name, blocks=False, fighter=None): 
     self.x = x 
     self.y = y 
     self.char = char 
     self.name = name 
     self.blocks = blocks 

     self.fighter = fighter 
     if self.fighter: 
      self.fighter.owner = self 


    def __repr__(self): 
     return "%s(x=%r, y=%r, char=%r, name=%r, blocks=%r fighter=%r)" % (self.__class__.__name__, self.x, self.y, self.char, self.name, self.blocks, self.fighter) 

class Fighter(yaml.YAMLObject): 
    yaml_tag = u'!Fighter' 
    #combat-related properties and methods (monster, player, NPC). 
    def __init__(self, hp, defense, strength): 
     self.hp = hp 
     self.base_defense = defense 
     self.base_strength = strength 
    def __repr__(self): 
     return "%s(hp=%r, defense=%r, strength=%r)" % (self.__class__.__name__, self.hp, self.defense, self.strength) 


monsters = {DungeonObject.name : DungeonObject for DungeonObject in yaml.load_all(data.monsterdata)} 
print (monsters) 

そして、私のYAMLファイル:これにより

monsterdata = """ 
--- 
!Fighter &fighter_component 
    hp: 20 
    defense: 0 
    strength: 4 
!DungeonObject 
    x: x 
    y: y 
    char: 'o' 
    name: 'orc' 
    blocks: True 
    fighter: fighter_component 
--- 
!Fighter &fighter_component 
    hp: 9 
    defense: 0 
    strength: 10 
!DungeonObject 
    x: x 
    y: y 
    char: 't' 
    name: 'troll' 
    blocks: True 
    fighter: fighter_component 
""" 

、私はエラーを取得しています: ラインここ

は、私がYAMLifyにしようとしているもののストリップダウン例です32、in monsters = {DungeonObject.name:ダンジョンオブジェクトのダンジョンオブジェクト(yaml.load_all(data.monsterdata)) AttributeError: 'Fighter'オブジェクトに 'name'属性がありません

答えて

1

各文書には、FighterDungeonObjectで構成されるシーケンス/リストが含まれている必要があります。前者は名前がないので、タイプDungeonObjectであり、タイプFighterではないDungeonObjectをフィルタリングする必要があります。

何ビットが混乱していることはあなたにも変数DungeonObjectを使用することで、その変数のdungeon_objectを使用しよう:

from ruamel import yaml 

monsterdata = """ 
--- 
- !Fighter &fighter_component 
    hp: 20 
    defense: 0 
    strength: 4 
- !DungeonObject 
    x: x 
    y: y 
    char: 'o' 
    name: 'orc' 
    blocks: True 
    fighter: fighter_component 
--- 
- !Fighter &fighter_component 
    hp: 9 
    defense: 0 
    strength: 10 
- !DungeonObject 
    x: x 
    y: y 
    char: 't' 
    name: 'troll' 
    blocks: True 
    fighter: fighter_component 
""" 


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

    def __init__(self, x, y, char, name, blocks=False, fighter=None): 
     self.x = x 
     self.y = y 
     self.char = char 
     self.name = name 
     self.blocks = blocks 

     self.fighter = fighter 
     if self.fighter: 
      self.fighter.owner = self 

    def __repr__(self): 
     return "{}(x={!r}, y={!r}, char={!r}, name={!r}, blocks={!r} fighter={!r})".format(
      self.__class__.__name__, self.x, self.y, self.char, self.name, 
      self.blocks, self.fighter) 


class Fighter(yaml.YAMLObject): 
    yaml_tag = u'!Fighter' 
    # combat-related properties and methods (monster, player, NPC). 

    def __init__(self, hp, defense, strength): 
     self.hp = hp 
     self.base_defense = defense 
     self.base_strength = strength 

    def __repr__(self): 
     return "{}(hp={!r}, defense={!r}, strength={!r})".format(
      self.__class__.__name__, self.hp, self.defense, self.strength) 

monsters = {} 
for doc in yaml.load_all(monsterdata, Loader=yaml.Loader): 
    for dungeon_object in doc: 
     if isinstance(dungeon_object, DungeonObject): 
      monsters[dungeon_object.name] = dungeon_object 

print (monsters) 

います:

{'orc': DungeonObject(x='x', y='y', char='o', name='orc', blocks=True fighter='fighter_component'), 'troll': DungeonObject(x='x', y='y', char='t', name='troll', blocks=True fighter='fighter_component')} 

を私は__repr__を更新より現代的な.format()メソッドを使用してください。私はruamel.yaml(PyYAML機能のスーパーセットであり、下位互換性があります)を使用しているので、ローダーを明示的に指定して、デフォルトローダーを使用するときにload_allが安全でないという警告を抑制する必要があります。 (免責事項:私はそのパッケージの開発者です)

+1

@Retro文字列の前後の引用符は、{{} 'の代わりに' {!r} 'を使用したものです。前者は '__repr__'(文字列の場合は引用符で囲まれた文字列)の結果を挿入し、後の場合は' __str__'の結果(文字列の場合は余分な引用符を含まない文字列)を挿入します。 – Anthon

+0

ブリリアント、それは多くを助けます - それはすべて今働きます。最終的な問題私は、ファイタークラスには、「ボーナス=合計(get_all_equipped(self.owner)内の装備の装備の装備の装備)」のような、「所有者」の使用を中心としたいくつかの方法があると考えている。 return self.base_strength + bonus' これは今、 'Fighter'オブジェクトにスローされます。属性 'owner'エラーはありません。 私は私のファイタークラス 'if self.fighter:self.fighter.owner'で定義しました。以前はうまくいきましたが、それ以上は動作しません。何か案は? – Retro

+1

'self'に所有者はなく、戦闘機のクラスであれば' get_all_equipped'のパラメータとして 'self.owner'を使うべきではなく、' self.fighter.owner'を使うべきです。しかし、それは実際のコードを見ることなく、単なる推測です。あなたのコードがリビジョン管理下にあることを確認し、定期的にコミットしてから、作業したものやロールバックしたものと比較することができます。 – Anthon