如何更新基类创建的属性?可变的默认参数,而不修改该参数?

发布于 2024-08-04 05:01:18 字数 1151 浏览 6 评论 0原文

我在新式类中发现了子类化和字典更新的一个奇怪问题:

Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on
win32
>>> class a(object):
...     def __init__(self, props={}):
...             self.props = props
...
>>> class b(a):
...     def __init__(self, val = None):
...             super(b, self).__init__()
...             self.props.update({'arg': val})
...
>>> class c(b):
...     def __init__(self, val):
...             super(c, self).__init__(val)
...
>>> b_inst = b(2)
>>> b_inst.props
{'arg': 2}
>>> c_inst = c(3)
>>> c_inst.props
{'arg': 3}
>>> b_inst.props
{'arg': 3}
>>>

在调试中,在第二次调用 (c(3)) 中,您可以在 a 中看到这一点构造函数 self.props 已经等于 {'arg': 2},之后调用 b 构造函数时,它就变成 {'arg': 3} 对于两个对象!

另外,构造函数调用的顺序是:

  a, b    # for b(2)
  c, a, b # for c(3)

如果将 b 中的 self.props.update() 替换为 self.props = {'arg': val}<​​/code> 构造函数,一切都会好的,并且会按预期运行,

但我确实需要更新这个属性,而不是替换它。

I've found a strange issue with subclassing and dictionary updates in new-style classes:

Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on
win32
>>> class a(object):
...     def __init__(self, props={}):
...             self.props = props
...
>>> class b(a):
...     def __init__(self, val = None):
...             super(b, self).__init__()
...             self.props.update({'arg': val})
...
>>> class c(b):
...     def __init__(self, val):
...             super(c, self).__init__(val)
...
>>> b_inst = b(2)
>>> b_inst.props
{'arg': 2}
>>> c_inst = c(3)
>>> c_inst.props
{'arg': 3}
>>> b_inst.props
{'arg': 3}
>>>

In debug, in second call (c(3)) you can see that within a constructor self.props is already equal to {'arg': 2}, and when b constructor is called after that, it becomes {'arg': 3} for both objects!

also, the order of constructors calling is:

  a, b    # for b(2)
  c, a, b # for c(3)

If you replace self.props.update() with self.props = {'arg': val} in b constructor, everything will be OK, and will act as expected

But I really need to update this property, not to replace it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

愛放△進行李 2024-08-11 05:01:18

props 不应该有这样的默认值。这样做:

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props

这是一个常见的 python "gotcha"

props should not have a default value like that. Do this instead:

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props

This is a common python "gotcha".

伊面 2024-08-11 05:01:18

您的问题出在这一行:

def __init__(self, props={}):

{} 是可变类型。在 python 中,默认参数值仅计算一次。这意味着您的所有实例都共享同一个字典对象!

要解决此问题,请将其更改为:

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props

Your problem is in this line:

def __init__(self, props={}):

{} is an mutable type. And in python default argument values are only evaluated once. That means all your instances are sharing the same dictionary object!

To fix this change it to:

class a(object):
    def __init__(self, props=None):
        if props is None:
            props = {}
        self.props = props
苏大泽ㄣ 2024-08-11 05:01:18

简短版本:执行此操作:

class a(object):
    def __init__(self, props=None):
        self.props = props if props is not None else {}

class b(a):
    def __init__(self, val = None):
        super(b, self).__init__()
        self.props.update({'arg': val})

class c(b):
    def __init__(self, val):
    super(c, self).__init__(val)

长版本:

函数定义仅计算一次,因此每次调用它时都会使用相同的默认参数。为了使其按照您的预期工作,每次调用函数时都必须评估默认参数。相反,Python 会生成一个函数对象一次,并将默认值添加到该对象中(如 func_obj.func_defaults

The short version: Do this:

class a(object):
    def __init__(self, props=None):
        self.props = props if props is not None else {}

class b(a):
    def __init__(self, val = None):
        super(b, self).__init__()
        self.props.update({'arg': val})

class c(b):
    def __init__(self, val):
    super(c, self).__init__(val)

The long version:

The function definition is evaluated exactly once, so every time you call it the same default argument is used. For this to work like you expected, the default arguments would have to be evaluated every time a function is called. But instead Python generates a function object once and adds the defaults to the object ( as func_obj.func_defaults )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文