【问题标题】:Mysteriously assigned constructor argument in iPython [duplicate]iPython中神秘分配的构造函数参数[重复]
【发布时间】:2020-11-30 14:16:43
【问题描述】:

这是我对 StackOverflow 的第一个问题。如果这个问题的格式不标准,请随时告诉我。

在了解iPython之后,我一直在从 Matlab 过渡到 Python。我使用 VSCode 和 Jupyter 界面以及“# %%”标头来获得交互式控制台。到目前为止,我热爱一切,我觉得我的工作需要完全过渡。

我在初始化类实例时遇到了一些神秘的问题。

假设我们有两个重新创建问题的最小文件:

ma​​in.py

# %%
%reset -f
from dummy import Dummy
dummy = Dummy()
print('created = %s' % dummy.others)
dummy.receive('something')
print('received = %s' % dummy.others)

dummy.py

class Dummy():
    def __init__(self, others=[]):
        self._others = others
        pass

    def receive(self, value):
        self._others.append(value)

    @property
    def others(self):
        return self._others

当我在重启 Jupyter 内核后第一次运行 main.py 时,我得到了

created = []
received = ['something']

这是完全可以预料的。但是,如果我再次运行它,我会得到

created = ['something']
received = ['something', 'something']

表示“虚拟”变量未按应有的方式初始化。

为了追查源头,我更改了脚本,以便

ma​​in.py(调试)

# %%
%reset -f

from dummy import Dummy
try:
    print(dummy.others)
except:
    print('dummy not found')

dummy = Dummy()
print('created = %s' % dummy.others)
dummy.receive('something')
print('received = %s' % dummy.others)

dummy.py(调试)

class Dummy():
    def __init__(self, others=[]):
        print('input = %s' % others)
        self._others = others
        print('internal = %s' % self._others)
        pass

    def receive(self, value):
        self._others.append(value)

    @property
    def others(self):
        return self._others

重新启动内核后运行主脚本时,我得到

dummy not found
input = []
internal = []
created = []
received = ['something']

和下面的又一次运行

dummy not found
input = ['something']
internal = ['something']
created = ['something']
received = ['something', 'something']

很明显,“%reset -f”后“dummy”变量被成功删除,但不知何故,Dummy构造函数中的输入参数“others”被分配给先前分配的,而不是“[]”。

但是为什么呢?

当我在 dummy.py 中更改“def receive(self, value)”时,我不再有问题了:

def receive(self, value):
    self._others = self._others + [value]

但是,如果我理解正确的话,这种变化是可变的。它应该会影响构造函数中的输入参数分配。

此外,当 Dummy 类位于同一文件 (main.py) 中时,不会出现此问题

你能告诉我我缺少什么吗?

编辑: 我现在明白我应该小心可变的初始化参数。但我的另一个基本问题是为什么 iPython 中的“%reset -f”没有清除所有内容。它确实删除了虚拟变量,但初始化参数“others”被神秘地分配给了前一个。魔法不是应该删除所有东西吗?

【问题讨论】:

  • 不要将参数的默认值设置为可变的,而是使用None 或哨兵对象。
  • 另外,__init__初始化器__new__ 是构造函数。
  • @Frodon:下面有更多问题。谢谢!
  • @chepner:我明白了……我以为它们是一样的。我需要谷歌找出它们之间的区别。谢谢!
  • 我的另一个问题是,为什么“%reset -f”没有完全删除所有内容。它确实设法删除了“虚拟”变量。但是为什么我分配了输入参数?

标签: python visual-studio-code ipython


【解决方案1】:

这是一个正确的 dummy.py 脚本,没有可变参数的默认值:

class Dummy():
    def __init__(self, others=None):
        self._others = others or []
        pass

    def receive(self, value):
        self._others.append(value)

    @property
    def others(self):
        return self._others

输出:

created = []
received = ['something']

【讨论】:

  • 谢谢。我今天学到了关于 Python 的新东西。但是,另一个基本问题是为什么 "%reset -f"" 没有完全删除 "dummy" 变量?该变量似乎已删除,但输入参数被奇怪地分配了。
  • 抱歉,我不知道 % resetl -f Jupyter 命令。