2011-08-28 12 views
10

No he podido averiguar cómo hacerlo en la documentación de PyYAML. Quiero representar las clases de Python que he definido en YAML, y tengo un valor predeterminado dado a un parámetro en el constructor si no está especificado en el YAML. Por ejemplo:Parámetros de constructor predeterminados en 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' 

que esperaba que crearía un objeto de prueba con barra = 3, pero supongo que no pasa por mi constructor cuando se crea el objeto. Si incluyo una asignación para bar en el YAML, todo funciona como se esperaba:

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

¿Alguien sabe cómo puedo tener que usar un valor por defecto?

Respuesta

9

Me encontré con el mismo problema: yaml_tag no funciona por alguna razón. Así que utilicé enfoque alternativo:

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 }""") 

Salida:

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

Sobre la base de la respuesta de alexanderlukanin13. Aquí está mi corte.

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 

A continuación, puede utilizar de esta manera:

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 
Cuestiones relacionadas