为什么构造一个新对象可能会更改该类的每个实例的字段?

尼尔

这是有问题的代码的简化版本:

class thing:
    def __init__(self, data1, data2={'foo': 1}):
        self.data2 = data2
        self.data2['bar'] = data1

datas = ['FIRST', 'SECOND']
things = [thing(x) for x in datas]
for p in things:
    print p.data2['bar']

希望此代码返回:

FIRST
SECOND

但是,它实际上返回:

SECOND
SECOND

为什么?


我最好的猜测是:

  • 我正在创建一本字典ur_dict = {'foo': 1}
  • 当我初始化类的对象时,thing不是在创建新的字典self.data2={'foo': 1},而是在初始化对的引用ur_dict
  • 并且在构造函数中将键值对添加bar: data1到时self.data2,实际上是在将键值对ur_dict自身添加。这将更新data2列表中每个单个对象字段。

我通过将以下代码段附加到上面的代码中来测试了这个假设:

things[0].data2['bar'] = 'FIRST'
for p in things:
    print p.data2['bar']

果然,结果是:

FIRST
FIRST

所以我认为我的假设可能是正确的,但对我来说仍然是个谜。我的问题似乎与这个问题非常相关-当我在构造函数中创建默认值时,该值是变量而不是实例变量吗?python为什么不为对象中参数的默认值创建新对象?有没有一种好的方法可以在将来概念化或捕获这种错误?有什么好的参考资料可了解此处的情况?

(如果我弄乱了行话,请提前道歉;我是接受正规教育的数学家。)


编辑:@CrazyPython[::-1]提到这是函数的属性,而不是类或对象。我创建了一个带有可变默认参数的函数示例,我试图找出如何以上面对对象和类的体验来破坏它。想到了这个:

EXPONENT = 1
def fooBar(x, y=EXPONENT):
    return x**y
print EXPONENT
print foo(5)
EXPONENT = 2
print EXPONENT
print foo(5)

但是,它返回:

1
5
2
5

什么是“破坏”这一点的好方法,以说明为什么不在此处使用可变的默认参数?

NoɥʇʎԀʎzɐɹƆ

self.data2={'foo': 1}是一个可变的默认参数。绝对不要那样做。99%的时间是错误的。

def foo(a, b={}):
    ...

不等于

def foo(a, b=None):
    if b is None:
        b = {}

b不是每次都重建。这是同一个对象。

有没有一种好的方法可以在将来概念化或捕获这种错误?

使用PyCharm或其他好的编辑器

当我在构造函数中创建默认值时,此值是类变量而不是实例变量吗?

不,不,不,不,不。它与函数绑定,而不与类或实例绑定。这是行为适用于所有功能。它与课程或链接的问题无关。

python为什么不为对象中参数的默认值创建新对象?

性能和兼容性。构造对象是一项潜在的昂贵操作。


附录

  • 请使用CamelCase进行授课。否则会违反PEP 8,这是Python官方样式指南。
  • 找一个体面的编辑。就个人而言,我建议使用PyCharm。(我不是推销员)是免费的。
    • PyCharm可以重命名变量,突出显示PEP 8错误,执行高级自动完成,类型检查,发现可变的默认参数等等。
  • 您不是继承自object那很糟。*

    为什么此python代码会更改列表每个对象的字段

  • 没有上下文,那是一个不好的称呼。它询问代码。当我们阅读标题时,我们没有代码。


使其更加清晰

声明函数时,将评估默认参数。(不是在执行时,而是在声明时)它们与函数绑定在一起。执行函数时,不会生成默认参数的副本。您可以直接修改默认参数。调用的下一个函数将接收相同的对象,并进行修改。

*您似乎是一名教授等。请不要因迷因而得罪。那只是从互联网上获得建议的风险。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

创建对象后,创建新对象会更改第一个对象的字段

来自分类Dev

为什么修改一个实例的值会更改另一个实例的值?

来自分类Dev

为什么一个新对象会影响当前对象?

来自分类Dev

为什么修改函数中的列表会更改原始列表,但是在函数中声明它们会创建一个新对象呢?

来自分类Dev

如何确保仅创建该类对象的一个实例?

来自分类Dev

为什么performSegueWithIdentifier总是创建一个新实例?

来自分类Dev

为什么一个人可能会在R脚本中多次加载一个库?

来自分类Dev

如何在该类中为该类的每个对象运行一个函数?

来自分类Dev

使用Java创建的每个新对象,将对象实例变量增加一个

来自分类Dev

使用Java创建的每个新对象,将对象实例变量增加一个

来自分类Dev

为什么我的程序总是会找到一个类,但是如果我在HTML中搜索该类,则该类不存在?

来自分类Dev

返回一个对象的新实例

来自分类Dev

Java问题:一个子类的构造函数中的计算会影响另一子类的实例的字段

来自分类Dev

创建一个新变量来标记R中绝对值更改的每个实例

来自分类Dev

实例化一个新对象或更改现有对象C#的值

来自分类Dev

为每个线程生成一个新的对象实例是否是线程安全的操作?

来自分类Dev

如何为每个对象实例创建一个新变量

来自分类Dev

分配该类的两个对象时,为什么调用构造函数?

来自分类Dev

为该类具有依赖关系的接口的每个具体实现组成一个类的实例

来自分类Dev

为什么每个I / O操作都创建一个新的Stream实例是一种好习惯?(C#)

来自分类Dev

为什么在python中不可能有一个object方法返回一个元组作为新对象__init__方法中的参数?

来自分类Dev

为什么在python中不可能有一个object方法返回一个元组作为新对象__init__方法中的参数?

来自分类Dev

一个或多个UTF8字段包含非UTF 8数据,编辑可能会产生意外的结果

来自分类Dev

为什么将对象分配给地图会产生一个空对象?

来自分类Dev

为什么不先通过实例的复制构造函数复制实例就持有一个实例不是一个好主意?

来自分类Dev

JSHint错误:一个或多个浏览器可能会静默删除此字符

来自分类Dev

通过链接构造函数实例化一个对象

来自分类Dev

什么可能会更改文件下载的缓存控制设置?

来自分类Dev

为什么`boost :: asio :: deadline_timer`为每个`deadline_timer`对象分配一个`timer_queue`实例?

Related 相关文章

  1. 1

    创建对象后,创建新对象会更改第一个对象的字段

  2. 2

    为什么修改一个实例的值会更改另一个实例的值?

  3. 3

    为什么一个新对象会影响当前对象?

  4. 4

    为什么修改函数中的列表会更改原始列表,但是在函数中声明它们会创建一个新对象呢?

  5. 5

    如何确保仅创建该类对象的一个实例?

  6. 6

    为什么performSegueWithIdentifier总是创建一个新实例?

  7. 7

    为什么一个人可能会在R脚本中多次加载一个库?

  8. 8

    如何在该类中为该类的每个对象运行一个函数?

  9. 9

    使用Java创建的每个新对象,将对象实例变量增加一个

  10. 10

    使用Java创建的每个新对象,将对象实例变量增加一个

  11. 11

    为什么我的程序总是会找到一个类,但是如果我在HTML中搜索该类,则该类不存在?

  12. 12

    返回一个对象的新实例

  13. 13

    Java问题:一个子类的构造函数中的计算会影响另一子类的实例的字段

  14. 14

    创建一个新变量来标记R中绝对值更改的每个实例

  15. 15

    实例化一个新对象或更改现有对象C#的值

  16. 16

    为每个线程生成一个新的对象实例是否是线程安全的操作?

  17. 17

    如何为每个对象实例创建一个新变量

  18. 18

    分配该类的两个对象时,为什么调用构造函数?

  19. 19

    为该类具有依赖关系的接口的每个具体实现组成一个类的实例

  20. 20

    为什么每个I / O操作都创建一个新的Stream实例是一种好习惯?(C#)

  21. 21

    为什么在python中不可能有一个object方法返回一个元组作为新对象__init__方法中的参数?

  22. 22

    为什么在python中不可能有一个object方法返回一个元组作为新对象__init__方法中的参数?

  23. 23

    一个或多个UTF8字段包含非UTF 8数据,编辑可能会产生意外的结果

  24. 24

    为什么将对象分配给地图会产生一个空对象?

  25. 25

    为什么不先通过实例的复制构造函数复制实例就持有一个实例不是一个好主意?

  26. 26

    JSHint错误:一个或多个浏览器可能会静默删除此字符

  27. 27

    通过链接构造函数实例化一个对象

  28. 28

    什么可能会更改文件下载的缓存控制设置?

  29. 29

    为什么`boost :: asio :: deadline_timer`为每个`deadline_timer`对象分配一个`timer_queue`实例?

热门标签

归档