【问题标题】:Is there a shortcut for `self.somevariable = somevariable` in a Python class constructor?Python 类构造函数中是否有 `self.somevariable = somevariable` 的快捷方式?
【发布时间】:2012-08-24 20:08:10
【问题描述】:

Python 中的构造函数通常如下所示:

class SomeClass:
    def __init__(self, a, b = None, c = defC):
        self.a = a
        self.b = b or []
        self.c = c

是否有这样的快捷方式,例如简单地定义__init__(self,**kwargs) 并将键用作self 的属性?

【问题讨论】:

  • 我知道一个构造函数中不应该有这么多不同的参数,这些参数不能逻辑地收集在字典中,这个问题更多是出于好奇

标签: python class constructor


【解决方案1】:

是的:

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

【讨论】:

  • 它会起作用,但正如BrenBarngnibbler 建议的那样,可能会有非常不方便的副作用
  • 不!仅当您选择locals() 解决方案时才会出现不便的副作用。使用**kwargs时不出现!
  • 没错,我指的是当a_method 是先前在SomeClass 中定义的一种方法时,可以执行brokenInstance = SomeClass(a_method = []) 之类的操作,即可能会意外修改不应该的类属性修改的。需要实施一些白名单或黑名单机制来防止这种情况发生
【解决方案2】:

我见过的一个成语是self.__dict__.update(locals())。如果您在方法的开头运行它,这将使用参数更新对象的字典(因为这些是方法开头的唯一局部变量)。如果你传入**kwargs,你可以传入self.__dict__.update(**kwargs)

当然,这是一种脆弱的方法。如果您不小心传入了一个掩盖现有属性的参数,它可能会导致令人费解的错误。例如,如果你的类有一个.doSomething() 方法并且你不小心将doSomething=1 传递给了构造函数,那么如果你尝试调用该方法,它将覆盖该方法并在以后导致错误。出于这个原因,最好不要这样做,除非在某些琐碎的情况下(例如,某种代理对象,其唯一目的是充当包含一些属性的“包”)。

【讨论】:

【解决方案3】:

一个问题

self.__dict__.update(locals())

是它包含self,所以你得到self.self。最好从locals() 中过滤掉self

例如。

vars(self).update((k,v) for k,v in vars().items() if k != 'self')

您可以防止使用这种变体意外覆盖方法

vars(self).update((k,v) for k,v in vars().items()
                   if k != 'self' and k not in vars(self))

如果你不想让它静默失败,你也可以像这样预先检查

if any(k in vars(self) for k in vars()):
    raise blahblah
vars(self).update((k,v) for k,v in vars().items() if k != 'self')

【讨论】:

  • 有趣的地方。所以也许像vars(self).update((k,v) for k,v in vars(self).items()) 这样的东西会确保只能设置已经存在的属性,然后使用一些代码来警告(甚至引发异常)关于尝试设置不应设置的属性的尝试。虽然我猜这仍然允许将类方法重新定义为BrenBarn stated
  • @Tobias,我添加了一个示例以避免覆盖类方法
  • 谢谢!早上太早了 - 我在发音 any(k m-/ 时笑了,所以稍微修改一下,甚至可以定义默认参数。但这确实表明在大多数情况下应该坚持self.var1 = var1
  • @Tobias,是的,通常显式更好。你怎么知道将None 翻译成[]self.b
  • 仅此一项可能是不这样做的最短理由。尽管一些for k in kwargs.keys() 和关键字白/黑名单和poping from a copy of **kwargs 可能会提供一些灵活性并以某种方式保持可读性。但是话又说回来,我想不出一个真实的应用程序,比方说,一个构造函数的十个命名参数,使用@classmethod定义不同的构造函数是不够的......
猜你喜欢
  • 2012-06-21
  • 2016-01-09
  • 1970-01-01
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 2018-05-14
  • 2016-12-20
  • 1970-01-01
相关资源
最近更新 更多