我一直在使用tkinter for gui进行蛇游戏。问题出在其中一个功能上。
该函数应该分别使用Canvas()。create_rectangle和Canvas()。create_oval绘制身体片段和水果。因此,我决定不编写每种情况的单独代码,而是决定编写一次,并仅使用“ shape”参数对其进行修改,该参数可以是“ rectangle”或“ oval”。函数还必须出于其自身目的返回绘制元素的id。最初,部分代码如下所示:
exec(
"""
segment_id = self.grid.create_{}(coords,
[coord + self.pxSize for coord in coords],
fill=color, tag=tag, width=0)
""".format(shape))
return segment_id
我得到了NameError: name 'segment_id' is not defined
,而不是普通的NameError: name 'self' is not defined
。
在谷歌搜索后,我只发现了这一点:
ldict = {}
exec('var = something', globals(), ldict)
var = ldict['var']
哪个解决NameError: name 'segment_id' is not defined
,但不解决另一个。因此,使用科学的戳方法,我通过将locals()传递给它的“ globals”参数来修复它。它有效,现在我感到更加困惑。
这是代码:
class Game(Tk):
def __init__(self):
...
# ...
def drawSegment(self, position, color, tag, shape, id_=None):
coords = self.field.from_1D_to_2D(position)
coords = [i * self.pxSize for i in coords]
# id > 1, otherwise deletes background
if id_ and id_ > 1:
self.grid.delete(id_)
# ???
ldict = {}
exec(
"""
segment_id = self.grid.create_{}(coords,
[coord + self.pxSize for coord in coords],
fill=color, tag=tag, width=0)
""".format(shape), locals(), ldict)
segment_id = ldict['segment_id']
return segment_id
# ...
我需要的是为什么起作用了,甚至怎么回事的答案。
答案 0 :(得分:4)
像这样使用exec是不必要的,并且您碰到过,相当混乱;所以我为您提供了两个不同的答案。
发生了什么事?
当您将globals=globals(), locals=ldict
传递给exec
时,它将在只能看到globals
和ldict
的范围内执行代码;因此,尤其是,它将看不到drawSegment
方法本地作用域本地的任何变量。由于self
仅在此本地范围内定义,因此为了从self
调用中引用exec
,您需要传递locals()
而不是{{1} }。
您应该怎么做?
您可以基于globals()
动态查找所需的create_ *方法,而不是根据shape
的值动态执行整个代码块:
shape
如果您知道形状的可能性只有两种,那么根据个人喜好,您可能会使它变得更加明显:
creator = getattr(self.grid, 'create_{}'.format(shape))
segment_id = creator(coords, [coord + self.pxSize for coord in coords],
fill=color, tag=tag, width=0)