【问题标题】:How do I copy **kwargs to self?如何将 **kwargs 复制到自己?
【发布时间】:2010-03-29 05:21:06
【问题描述】:

有没有一种方法可以定义__init__,以便将**kwargs 中定义的关键字分配给类?

例如,如果我要使用 ValidationRule(other='email') 初始化 ValidationRule 类,则应将 self.other 的值添加到类中,而不必显式命名每个可能的 kwarg。

class ValidationRule:
    def __init__(self, **kwargs):
        # code to assign **kwargs to .self

【问题讨论】:

  • 你不使用新式类有什么原因吗?
  • @Georg:我什至不知道什么是新式类?如果相关,我正在使用 Python 2.5。
  • 要创建一个新样式类,您只需要从一个新样式类(通常是object)继承,所以请使用class ValidationRule(object): 更多信息:python.org/doc/newstyle
  • 新式..?似乎是python3中的旧风格?这甚至可以在那里工作吗?

标签: python syntax constructor keyword-argument


【解决方案1】:

我想somewhere on the stackoverflow 我见过这样的解决方案。无论如何它可能看起来像:

class ValidationRule:
    __allowed = ("other", "same", "different")
    def __init__(self, **kwargs):
        for k, v in kwargs.iteritems():
            assert( k in self.__class__.__allowed )
            setattr(self, k, v)

这个类只接受__allowed中列出的白名单属性名称的参数。

【讨论】:

  • ValidationRule 只是我的基类,它没有任何自己的属性,所以它们不会意外覆盖任何东西,但否则,这将是一个很好的安全防护;)不过,在这种情况下,我可能会使用黑名单而不是白名单,以免限制太多。
  • Python-3 重命名dict.iteritems -> dict.items, more information
  • 我不知道这是否是 python3 问题,但在 python 3.8 中发送无效的kwargs 会引发AssertionError。我使用try...catch 来克服这个问题
  • @Mr.Hobo,您应该能够看到断言的来源,并且很可能会导致行 assert( k in self.__class__.__allowed ) 在那里证明关于验证的答案的最后一句话是正确的,它是它的唯一作用;)即如果您不喜欢它,可以将其删除或用不同的处理方式替换。
【解决方案2】:

这可能比更新__dict__ 更好:

class C:
    def __init__(self, **kwargs):
        vars(self).update(kwargs)

>>> c = C(a='a', b='b')
>>> c.a   # returns 'a'
>>> c.b   # returns 'b'

【讨论】:

    【解决方案3】:

    这可能不是最干净的方法,但它有效:

    class ValidationRule: 
        def __init__(self, **kwargs): 
            self.__dict__.update(kwargs)
    

    我想我更喜欢ony's solution,因为它限制了可用属性,以免您的输入来自外部来源时遇到麻烦。

    【讨论】:

    • 如果变量是“魔术”变量,它将无法正常工作。考虑propetiesslotted objects。这适用于 Python 2 和 Python 3。
    【解决方案4】:

    你可以这样做:

    class ValidationRule:
       def __init__(self, **kwargs):
          for (k, v) in kwargs.items():
             setattr(self, k, v)
    

    【讨论】:

    • 如果 kwargs 列表很长,您可能希望使用 iteritems() 而不是 items()。出于您的目的,这应该没问题。
    • @GeorgSchölly iteritems()items() 有什么区别?
    • @StevenVascellaro 在 Python 2 iteritems() 中,返回一个生成器,而 items() 返回一个列表。在 Python 3 中,items() 返回一个项目视图,iteritems() 已被删除。我更喜欢items(),因为它兼容两者。对于非常大的字典,我仍然使用iteritems()。另见stackoverflow.com/questions/13998492/iteritems-in-python
    【解决方案5】:

    您可以通过更新实例的__dict__ 属性来设置您的kwargs 参数。

    class ValidationRule:
       def __init__(self, **kwargs):
           self.__dict__.update(kwargs)
    

    【讨论】:

      【解决方案6】:
      class ValidationRule:
         def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
      

      【讨论】:

        【解决方案7】:

        我发现上面的答案很有帮助,然后改进了:

        class MyObj(object):
            def __init__(self, key1=1, key2=2, key3=3):
                for (k, v) in locals().iteritems():
                    if k != 'self':
                        setattr(self, k, v)
        

        测试:

        >>> myobj = MyObj(key1=0)
        >>> print myobj.key1
        0
        

        还有验证:

        >>> myobj = MyObj(key4=4)
        TypeError: __init__() got an unexpected keyword argument 'key4'
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-15
          • 2011-08-10
          • 2021-12-30
          • 2022-07-11
          • 2021-09-12
          • 1970-01-01
          相关资源
          最近更新 更多