【问题标题】:Default constructor parameters in pyyamlpyyaml 中的默认构造函数参数
【发布时间】:2011-11-05 15:29:36
【问题描述】:

我无法在 PyYAML 文档中找到如何执行此操作。我想表示我在 YAML 中定义的 python 类,并且如果在 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 创建一个Test 对象,但我猜它在创建对象时会绕过我的构造函数。如果我在 YAML 中包含 bar 的映射,一切都会按预期工作:

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

有谁知道我如何让它使用默认值?

【问题讨论】:

    标签: python tags yaml pyyaml


    【解决方案1】:

    我遇到了同样的问题: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)]
    

    【讨论】:

      【解决方案2】:

      基于 alexanderlukanin13 的回答。这是我的剪辑。

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-10
        • 2012-06-30
        • 2014-07-09
        • 1970-01-01
        • 2012-02-26
        • 2016-06-05
        • 2016-01-06
        • 2018-02-02
        相关资源
        最近更新 更多