Python3。“ exec”功能令人困惑的问题

时间:2020-01-05 02:12:42

标签: python tkinter scopes

我一直在使用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

    # ...

我需要的是为什么起作用了,甚至怎么回事的答案。

1 个答案:

答案 0 :(得分:4)

像这样使用exec是不必要的,并且您碰到过,相当混乱;所以我为您提供了两个不同的答案。

发生了什么事?

当您将globals=globals(), locals=ldict传递给exec时,它将在只能看到globalsldict的范围内执行代码;因此,尤其是,它将看不到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)
相关问题