Параметры конструктора по умолчанию в pyyaml
Я не смог узнать, как это сделать в документации PyYAML. Я хочу представлять классы python, определенные в YAML, и иметь значение по умолчанию, заданное параметру в конструкторе, если он не указан в YAML. Например:
>>> 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'
Я ожидал, что он создаст тестовый объект с bar=3, но я предполагаю, что он обходит Мой конструктор, когда он создает объект. Если я включу отображение для бара в ЯМЛ, все будет работать, как и ожидалось:
>>> yaml.load("""
... --- !Test
... foo: 5
... bar: 42
... """)
Test(foo=5, bar=42)
Делает кто-нибудь знает, как я могу заставить его использовать значение по умолчанию?
2 ответа:
Я столкнулся с той же проблемой: yaml_tag почему-то не работает. Поэтому я использовал альтернативный подход:
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 }""")
Вывод:
[Test(foo=1, bar=3), Test(foo=10, bar=20)]
На основании ответа Александра луканина13. Вот моя доля.
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
Затем вы можете использовать его следующим образом:
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