2011-08-28 4 views
10

Je n'ai pas pu trouver de méthode dans la documentation PyYAML. Je veux représenter les classes python que j'ai définies dans YAML, et avoir une valeur par défaut donnée à un paramètre dans le constructeur s'il n'est pas spécifié dans le YAML. Par exemple:Paramètres constructeurs par défaut dans pyyaml ​​

>>> class Test(yaml.YAMLObject): 
...  yaml_tag = u"!Test" 
...  def __init__(self, foo, bar=3): 
...    self.foo = foo 
...    self.bar = bar 
...  def __repr__(self): 
...    return "%s(foo=%r, bar=%r)" % (self.__class__.__name__, self.foo, self.bar) 
... 
>>> yaml.load(""" 
... --- !Test 
... foo: 5 
... """) 
Traceback (most recent call last): 
    File "<stdin>", line 4, in <module> 
    File "<stdin>", line 7, in __repr__ 
AttributeError: 'Test' object has no attribute 'bar' 

Je pensais que ce serait créer un objet de test avec bar = 3, mais je suppose que ce court-circuite mon constructeur quand il crée l'objet. Si j'inclure un mappage pour un bar dans le YAML, tout fonctionne comme prévu:

>>> yaml.load(""" 
... --- !Test 
... foo: 5 
... bar: 42 
... """) 
Test(foo=5, bar=42) 

Est-ce que quelqu'un sait comment je peux l'avoir utiliser une valeur par défaut?

Répondre

9

J'ai rencontré le même problème: yaml_tag ne fonctionne pas pour une raison quelconque. Donc, je approche alternative:

import yaml 

def constructor(loader, node) : 
    fields = loader.construct_mapping(node) 
    return Test(**fields) 

yaml.add_constructor('!Test', constructor) 

class Test(object) : 
    def __init__(self, foo, bar=3) : 
     self.foo = foo 
     self.bar = bar 
    def __repr__(self): 
     return "%s(foo=%r, bar=%r)" % (self.__class__.__name__, self.foo, self.bar) 

print yaml.load(""" 
- !Test { foo: 1 } 
- !Test { foo: 10, bar: 20 }""") 

Sortie:

[Test(foo=1, bar=3), Test(foo=10, bar=20)] 
0

Sur la base de la réponse de alexanderlukanin13. Voici ma coupe.

import yaml 

YAMLObjectTypeRegistry = {} 

def register_type(target): 
    if target.__name__ in YAMLObjectTypeRegistry: 
     print "{0} already in registry.".format(target.__name__) 
    elif 'yaml_tag' not in target.__dict__.keys(): 
     print target.__dict__ 
     raise TypeError("{0} must have yaml_tag attribute".format(
      target.__name__)) 
    elif target.__dict__['yaml_tag'] is None: 
     pass 
    else: 
     YAMLObjectTypeRegistry[target.__name__] = target 
     yaml.add_constructor(
       target.__dict__['yaml_tag'], 
       lambda loader, node: target(**loader.construct_mapping(node))) 
     print "{0} added to registry.".format(target.__name__) 

class RegisteredYAMLObjectType(type): 
    def __new__(meta, name, bases, class_dict): 
     cls = type.__new__(meta, name, bases, class_dict) 
     register_type(cls) 
     return cls 

class RegisteredYAMLObject(object): 
    __metaclass__=RegisteredYAMLObjectType 
    yaml_tag = None 

Vous pouvez alors l'utiliser comme ceci:

class MyType(registry.RegisteredYAMLObject): 
    yaml_tag = u'!mytype' 
    def __init__(self, name, attr1='default1', attr2='default2'): 
     super(MyType, self).__init__() 
     self.name = name 
     self.attr1 = attr1 
     self.attr2 = attr2 
Questions connexes