【问题标题】:Python 3. Confusing issue with 'exec' functionPython 3. 'exec' 函数令人困惑的问题
【发布时间】:2020-04-23 01:47:26
【问题描述】:

我一直在使用 tkinter for gui 开发我的蛇游戏。问题出在其中一个函数上。

该函数应该分别使用 Canvas().create_rectangle 和 Canvas().create_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 'self' is not defined,而不是普通的NameError: name 'segment_id' is not defined

谷歌搜索后,我只发现了这个:

ldict = {}
exec('var = something', globals(), ldict)
var = ldict['var']

解决了NameError: name 'segment_id' is not defined,但没有解决另一个问题。因此,使用科学的 poke 方法,我通过将 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

    # ...

我需要的是关于为什么会起作用以及发生了什么的答案。

【问题讨论】:

  • 为什么要这样使用exec
  • 抱歉,我不明白这与exec 有什么关系。请提供更完整的代码sn-p,以及完整的错误信息,以便我们了解更多。
  • 你知道globals()locals()是什么意思吗?
  • 至少你可以写segment_id = getattr(self.grid, 'create_{}'.format(shape))(coords, ...)。不要使用exec 来避免普通查找。

标签: python tkinter scopes


【解决方案1】:

像这样使用 exec 是不必要的,而且正如您所遇到的那样,相当混乱;所以我有两个不同的答案给你。

发生了什么事?

当你将globals=globals(), locals=ldict传递给exec时,它会在一个只能看到globalsldict的范围内执行代码;所以特别是,它不会看到drawSegment 方法本地范围内的任何变量。由于self 仅在此本地范围内定义,为了从您的exec 调用中引用self,您需要传入locals(),而不仅仅是globals()

你应该怎么做?

您无需根据shape 的值动态执行整个代码块,而是可以根据shape 动态查找所需的create_* 方法:

creator = getattr(self.grid, 'create_{}'.format(shape))
segment_id = creator(coords, [coord + self.pxSize for coord in coords],
                     fill=color, tag=tag, width=0)

如果您知道形状只有两种可能性,根据个人喜好,您可能会更加明显:

creator = self.grid.create_oval if shape == 'oval' else self.grid.create_rectangle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 2011-10-13
    相关资源
    最近更新 更多