jupyter 笔记本中 python 的奇怪行为;这是一个错误还是我应该接受它?

Weird behaviour with python in jupyter notebook; is this a bug or should I just accept it as it is?

当我偶然发现一些奇怪的行为时,我正在修补 jupyter notbook 中的一个小项目想法...... 以下代码摘自原文

class MyClass:
    Instances = []
    
    def __init__(self,name=None):
        self.id = len(MyClass.Instances)
        MyClass.Instances.append(self)
        
        if name is None:
            self.name = 'Class %s' % self.id
        else:
            self.name = name
    
    def show(self):
        print('Name: %s\nId: %s' % (self.name, self.id))

    def instance_at(i : int):
        if i >= len(MyClass.Instances):
            raise ValueError("Instance does not exist")
        return MyClass.Instances[i]

(我希望代码是不言自明的)

我 运行 单元格并测试了代码,它工作正常:

In [24] :   m = MyClass()
            m.show()

Out [25] :  Name: Class 0
            Id: 0

扭曲:

我不喜欢第一个实例,没有给出名字,会被称为 'Class 0' 所以我心想:'Why not add an object which will act as a placeholder for the index 0'(不要问我为什么这样做,'真是个脑残)。

所以我将第 2 行更改为 Instances = [MyClass(name='id')。这也有效,但是当我尝试在索引 0 处接收实例时,它的 id 值与我预期的不同。

In [24] :   m = MyClass()
            m.show()
            MyClass.instance_at(0).show()

Out [25] :  Name: Class 0
            Id: 1
            Name: id
            Id: 1

这就是我决定在另一个笔记本中编写我的代码的更通用版本(此处显示的代码)的原因。我在 运行 单元格之前完整地写了它,包括 Instances = [MyClass(name='id')].

这次我得到了这个:

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-60020e1975a4> in <module>
----> 1 class MyClass:
      2     Instances = [MyClass(name='id')]
      3     #Instances = []
      4 
      5     def instance_at(i : int):

<ipython-input-1-60020e1975a4> in MyClass()
      1 class MyClass:
----> 2     Instances = [MyClass(name='id')]
      3     #Instances = []
      4 
      5     def instance_at(i : int):

NameError: name 'MyClass' is not defined

所以现在我有一段代码可以在一个笔记本上运行,但不能在另一个笔记本上运行。至少当你简单地复制和粘贴它时。在 jupyter notebook 中,这可以通过将第 2 行更改为 Instances = []、运行 单元格并将其改回来解决。

我相当确定这是因为 class 和 class 变量 Instances 在我创建不明确的代码行之前已经存在。

事后看来,这确实有道理,我怀疑意外的 id 值来自创建实例 m 时在列表中发现的构造函数调用。

我错了吗?谁能详细说说?

如果这样的post在这里不合适,请告诉我。

一个更简单的例子:

class Example:
    def __init__(self):
        print("Creating an instance of the OLD class")

class Example: # redefining like this does **not** cause an error
    Instances = [Example()]
    def __init__(self):
        print("Creating an instance of the NEW class")
    
# the OLD message is printed immediately
# because `Instances = [Example()]` uses the previous definition
# because it **cannot** use the current one; it hasn't been created yet.

# You **do** get an error **without** the old definition, because then
# there isn't a definition at all.

x = Example() # the NEW message is printed
# the OLD class **still exists**, but cannot easily be accessed.
# As long as we can think of a way to get at an instance,
# we can use the `__class__` of the instance to create more;
# and we can rename that to make it easily usable:
Old_Example = Example.Instances[0].__class__
y = Old_Example()