PythonWin的交互式Python shell为何调用构造函数两次?

3 投票
3 回答
1009 浏览
提问于 2025-04-11 09:16

在回答Python中的静态类变量这个问题时,

我发现PythonWin的PyWin32版本209.2的解释器似乎会执行两次?

PythonWin 2.5 (r25:51908, Mar  9 2007, 17:40:28) [MSC v.1310 32 bit (Intel)] on win32.
Portions Copyright 1994-2006 Mark Hammond - see 'Help/About PythonWin' for further copyright information.
>>> class X:
...     l = []
...     def __init__(self):
...         self.__class__.l.append(1)
...         
>>> X().l
[1, 1]
>>> 

而Python的解释器却能正确处理这个问题。

C:\>python
ActivePython 2.5.0.0 (ActiveState Software Inc.) based on
Python 2.5 (r25:51908, Mar  9 2007, 17:40:28) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class X:
...   l = []
...   def __init__(self):
...     self.__class__.l.append(1)
...
>>> X().l
[1]
>>>

3 个回答

1

还有两个小补充点。

首先,self.__class__.l.append(1) 这个写法其实不太合理。

直接用 self.l.append(1) 就可以了。Python 会先在实例里找这个变量,如果找不到再去类里找。

更重要的是,类级别的变量一般用处不大。类级别的常量有时候可以用,但即使这样也很难说得通。

在 C++ 和 Java 里,类级别的(static)变量看起来很方便,但其实没什么实质性的价值。教新手的时候也很难,常常会浪费很多时间在细节上,而且不太实用。如果你想知道创建了多少个 X,可能更好的办法是创建一个 XFactory 类,而不是依赖类变量。

class XFactory( object ):
    def __init__( self ):
        self.listOfX= []
    def makeX( self, *args, **kw ):
        newX= X(*args,**kw)
        self.listOfX.append(newX)
        return newX

这样就没有类级别变量的奇怪问题了。而且,这样也不会把单个的 X 和一堆 X 混在一起。从长远来看,我觉得一个类既是某个东西又是某个东西的集合会让人感到困惑。

简单的比复杂的好。

2

Dave Webb 说得对,你可以通过添加一个打印语句来验证这一点:

>>> class X:
...     l = []
...     def __init__(self):
...             print 'inited'
...             self.__class__.l.append(1)
...             

然后,当你在 X(). 后面输入一个句点时,它会先打印出 inited,然后再给你显示补全的提示框。

3

我猜测是这样的。PythonWin编辑器提供了自动补全功能,也就是说,当你输入 myobject. 时,它会弹出一个小窗口,显示所有可用的方法名称。所以我认为当你输入 X(). 时,它在后台创建了一个 X 的实例,并执行了 dir 或类似的操作来查找这个对象的属性。

因此,构造函数实际上只会为每个对象运行 一次,但为了让你能够互动,它在后台默默地创建对象,而不会告诉你。

撰写回答