Skip to main content
 首页 » 编程设计

Python,实例没有 __call__ 方法

2025年05月04日13zhenyulu

我在 python2.7 中使用 tkinter。我想要做的就是在一个类中绘制一个 Canvas ,然后在另一个类中绘制一个 Canvas ,该类将在 Canvas 周围移动一个正方形。但出于某种原因,我得到了

Exception in Tkinter callback 
Traceback (most recent call last): 
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__ 
    return self.func(*args) 
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 495, in callit 
    func(*args) 
AttributeError: Animation instance has no __call__ method 

据我所见,当人们过度使用一个值或一个名称遮盖另一个值时,他们会出现此错误。但我看不出我可能骑过头了。其他人能看到问题吗?

驱动.py:

from Tkinter import * 
import animation 
class Alien(object): 
    def __init__(self): 
        #Set up canvas 
        self.root = Tk() 
        self.canvas = Canvas(self.root, width=400, height=400) 
        self.canvas.pack() 
        #Vars 
        self.map = [[1, 0, 0, 1, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 1, 0, 0], [1, 0, 0, 1, 0]] 
        self.x = 0 
        self.y = 0 
        r = 50 
        land = {} 
        #Draw Init 
        for i, row in enumerate(self.map): 
            for j, cell in enumerate(row): 
                color = "black" if cell else "green" 
                land[(i, j)] = self.canvas.create_rectangle(r * i, r * j , r * (i + 1), r * (j + 1), 
                                             outline=color, fill=color) 
        self.creature = self.canvas.create_rectangle(r * self.x, r * self.y, r * (self.x + 1), r * (self.y + 1), 
                                                     outline="red", fill="red") 
        self.canvas.pack(fill=BOTH, expand=1) 
        #Action 
        self.root.after(0, animation.Animation(self.root, self.canvas, self.creature)) 
        #Clost TK 
        self.root.mainloop() 
a = Alien() 

动画.py:

from random import randrange 
 
 
    class Animation(): 
        def __init__(self, root, canvas, creature): 
            self.x = self.y = 0 
            i = randrange(1, 5) 
            if i == 1: 
                self.y = -1 
            elif i == 2: 
                self.y = 1 
            elif i == 3: 
                self.x = -1 
            elif i == 4: 
                self.x = 1 
            self.canvas = canvas 
            self.creature = creature 
            for i in range(10): 
                root.after(250, self.animate()) 
 
        def animate(self): 
                #root.after(250, self.animate(canvas, creature)) 
                """Moves creature around canvas""" 
                self.canvas.move(self.creature, self.x * 50, self.y * 50) 
                #self.canvas.update() no longer needed 

请您参考如下方法:

您将一个 Animation 实例传递给 after,然后它会尝试调用它。我怀疑您是想创建一个实例,然后传入它的 animate 方法,对吗?

编辑:既然我回到了互联网上,那么详细说明一下;问题出在这一行:

self.root.after(0, animation.Animation(self.root, self.canvas, self.creature)) 

这将创建一个 Animation 实例并将其传递给 after 方法,然后当无法弄清楚如何调用它时该方法就会崩溃。我会做类似的事情:

animator = animation.Animation(self.root, self.canvas, self.creature) 
self.root.after(0, animator.animate) # get things going 

此外,正如其他地方所指出的,Animation 构造函数中的循环至少以两种方式被破坏:

for i in range(10): 
    root.after(250, self.animate()) 

设置十个回调,全部相对于当前时间——即在四分之一秒后,您将同时触发十个回调。它们都会失败,因为您正在调用 animate 方法并将其返回值(None)传递给 after,而不是传递方法本身。或者换句话说,

after(ms, function()) 

与

相同
value = function() 
after(ms, value) 

这不是你真正想要的。解决此问题的一种方法是将 self.root = root 添加到构造函数中,然后执行以下操作:

self.root.after(250, self.animate) 

在 animate 中触发四分之一秒后的另一个调用。

或者,您可以让 Tkinter 为您跟踪事情; after 方法允许您将参数传递给回调,您可以使用它来传递 after 函数本身 (!) 所以 animate 方法不必寻找它:

def animate(self, after): 
    ... do animation ... 
    after(250, self.animate, after) 

然后通过调用 root.after 将其关闭,传入该方法:

root.after(0, animator.animate, root.after)