jupyter notebook 中 python 的奇怪行为;这是一个错误还是我应该接受它?
Posted
技术标签:
【中文标题】jupyter notebook 中 python 的奇怪行为;这是一个错误还是我应该接受它?【英文标题】:Weird behaviour with python in jupyter notebook; is this a bug or should I just accept it as it is? 【发布时间】:2021-11-11 21:09:48 【问题描述】:当我偶然发现一些奇怪的行为时,我正在对 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',所以我想:'为什么不添加一个对象作为索引 0 的占位符'(Don '不要问我为什么这样做,'这是一个脑残)。
所以我将第 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 = []
、运行单元并将其改回来解决。
我相当肯定这是因为在我创建模棱两可的代码行之前,类和类变量 Instances
已经存在。
事后看来,这确实是有道理的,我怀疑意外的 id 值来自创建实例 m
时在列表中发现的构造函数调用。
我错了吗?谁能详细说明一下?
如果这样的帖子在这里不合适,请告诉我。
【问题讨论】:
“所以我将第 2 行更改为Instances = [MyClass(name='id')
。这也有效”这是不可重现的。这样做将不使用您当前正在编写的MyClass
的定义。它将使用 previous MyClass
,如果它在您的会话中仍然可用;如果您重新启动并尝试使用这样的类(或在新的源文件中从头开始),则会产生错误。
"这次我得到了这个:...所以现在我有一段代码可以在一个笔记本上运行,但不能在另一个笔记本上运行。"那是因为它实际上并没有像你所期望的那样“工作”,而是“在一个笔记本中”你还没有开始新鲜。
也就是说:试图“自动注册”您为类创建的每个实例几乎肯定是一个设计错误。只需让调用代码列出部分代码关心的实例。根据整体代码结构,这可能是也可能不是全部。
【参考方案1】:
一个更简单的例子:
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()
【讨论】:
以上是关于jupyter notebook 中 python 的奇怪行为;这是一个错误还是我应该接受它?的主要内容,如果未能解决你的问题,请参考以下文章
在Jupyter notebook中使用特定虚拟环境中的python的kernel
Jupyter Notebook安装新python kernel