导致属性错误的原因:'classObject'对象没有属性'_w'是什么?

2 投票
2 回答
6622 浏览
提问于 2025-04-16 15:25

我正在使用Python 3.1,想要创建一个游戏。我创建了一个叫做 class Board(Canvas): 的类。为什么要这样做呢?因为我需要通过“标签”来跟踪棋子。但是,当我尝试将标签绑定到棋子时,出现了一个错误提示,内容大概是这样的……

Traceback (most recent call last):
File "/Users/bluedragon1223/Desktop/Djambi0-2.py", line 282, in <module>
x = Board()
File "/Users/bluedragon1223/Desktop/Djambi0-2.py", line 94, in __init__
self.tag_bind(self.canM, '<1>', _onPieceClick)
File "/Library/Frameworks/Python.framework/Versions/3.1/lib/python3.1/tkinter/__init__.py",
line 2103, in tag_bind
return self._bind((self._w, 'bind', tagOrId),
AttributeError: 'Board' object has no attribute '_w'

我能跟着代码一路走到出错的地方,但我觉得我不太明白这里的'_w'是什么。

x = Board() 之后,def __init__(self, window=mainWin): 里面有 self.M = PhotoImage(file=path+'M.gif')。然后 self.M 被用到:

    def __draw(self):
    canvas = Canvas(mainWin,width=810,height=810)
    for i in range(9):
        canvas.create_line(90*i,0,90*i,810)
    for j in range(9):
        canvas.create_line(0,90*j,810,90*j)
    canvas.create_rectangle(3,810,810,3)
    canvas.bind('<1>', _point2square)
    canvas.pack()
    self.canM = canvas.create_image(405,405,image=self.M,tag = 'M')

之后,它在 self.tag_bind(self.canM, '<1>', _onPieceClick) 中被使用。错误就是在这里出现的。我的问题是,为什么会这样?我做错了什么,怎么才能修复它?

非常感谢任何帮助!

2 个回答

0

作为一个TKinter初学者,我经常遇到这个错误,所以我想分享一下我是怎么解决这个错误的,而不是解释它为什么会出现。

在绑定事件的时候,我用到了一个lambda,结果我传入了一个函数的声明,而不是直接调用这个函数。

layout.bind("<Return>",lambda event: self.handleInput)

AttributeError: 'layout' object has no attribute '_w'

加上一个手动调用这个函数后,它就正常工作了,没有错误。

layout.bind("<Return>",lambda event: self.handleInput())

去掉lambda后,函数可以按预期执行,只用声明就可以了,但这又出现了另一个错误。

layout.bind("<Return>",self.handleInput)

handleInput() takes 1 positional argument but 2 were given

为了解决这个问题,我在handleInput函数中添加了第二个参数。虽然这可能会多出一个没用的参数,但这样就解决了错误。

def handleInput(self,event):
    print('works')
4

在tkinter中,像画布这样的对象其实只是一个代理对象,用来代表真正的tk小部件。它的属性_w里面存储的是这个真实tk小部件的内部名称。例如:

$ python2.5
Python 2.5.4 (r254:67917, Dec 23 2008, 14:57:27) 
[GCC 4.0.1 (Apple Computer, Inc. build 5363)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import Tkinter as tk
>>> root=tk.Tk()
>>> canvas = tk.Canvas(root)
>>>> print canvas._w
.8327736

如果你遇到错误提示object has no attribute '_w',这意味着你创建了一个对象实例,它认为自己是一个tk小部件(所以有像tag_bind这样的功能),但实际上并没有和任何tk小部件关联起来。

这种情况可能发生在你创建了一个tkinter小部件的子类,但没有调用父类的__init__方法。例如,像这样做会出现类似的错误(注意我没有在Canvas类上调用__init__):

>>> class Board(tk.Canvas):
...     def __init__(self, *args):
...         pass         
...     
>>> board = Board()
>>> board.tag_bind("whatever","<1>", None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-tk
/Tkinter.py", line 2129, in tag_bind
return self._bind((self._w, 'bind', tagOrId),
AttributeError: Board instance has no attribute '_w'

我猜你可能在做类似的事情。你把Board定义为Canvas的子类,但没有调用Canvas.__init__方法(或者调用了但忽略了它抛出的任何错误)。

撰写回答