【问题标题】:NameError using execfile in pythonNameError 在 python 中使用 execfile
【发布时间】:2010-10-29 16:53:03
【问题描述】:

我的应用程序有一个使用 execfile 动态执行 python 脚本的按钮。如果我在脚本中定义一个函数(例如 spam())并尝试在另一个函数中使用该函数(例如 eggs()),我会收到此错误:

NameError: global name 'spam' is not defined

eggs() 中调用 spam() 函数的正确方法是什么?

#mainprogram.py
class mainprogram():
    def runme(self):
        execfile("myscript.py")

>>> this = mainprogram()
>>> this.runme()

# myscript.py
def spam():
    print "spam"

def eggs():
    spam()

eggs()

另外,我似乎无法从脚本中的主应用程序执行方法。即

#mainprogram.py
class mainprogram():
    def on_cmdRunScript_mouseClick( self, event ):
        execfile("my2ndscript.py")
    def bleh():
        print "bleh"

 #my2ndscript.py
 bleh()

错误是:

NameError: name 'bleh' is not defined

my2ndscript.py 调用 bleh() 的正确方法是什么?

编辑:更新第一期

【问题讨论】:

  • 无法重现第一个问题 - 将您的文本复制到 /tmp/zau 并运行 execfile('/tmp/zau') 对我来说很好。第二个问题是您的错误- bleh 不是全局函数,而是类 mainprogram 的(错误定义的)方法;如果你把 bleh 变成一个静态方法,脚本将能够调用 mainprogram.bleh() [仍然不是裸名 'bleh()' 因为,事实上,这个裸名没有被定义,这个名字只在类内部定义)。
  • 第一期的execfile也在一个类里面。查看更新的问题。

标签: python class scope namespaces


【解决方案1】:

在第二种情况下,您将需要import(不确定“mainprogram.py”是否 在你的$PYTHONPATH)

#mainprogram.py
class mainprogram:
    def runme(self):
        execfile("my2ndscript.py")
    def bleh(self):
        print "bleh"
if __name__ == '__main__':
    mainprogram().runme()

#my2ndscript.py
import mainprogram
x = mainprogram.mainprogram()
x.bleh()

但这将创建mainprogram 的第二个实例。或者,更好的是:

#mainprogram.py
class mainprogram:
    def runme(self):
        execfile("my2ndscript.py", globals={'this': self})
    def bleh(self):
        print "bleh"
if __name__ == '__main__':
    mainprogram().runme()

#my2ndscript.py
this.bleh()

我猜execfile 无论如何都不是解决您问题的正确方法。 为什么不使用import__import__(以及reload(),以防脚本在这些点击之间发生变化)?

#mainprogram.py
import my2ndscript

class mainprogram:
    def runme(self):
        reload(my2ndscript)
        my2ndscript.main(self)
    def bleh(self):
        print "bleh"

if __name__ == '__main__':
    mainprogram().runme()

#my2ndscript.py
def main(program):
    program.bleh()

【讨论】:

    【解决方案2】:

    Addy689 解释了真正的问题:它出现在 从函数 调用 execfile() 时。 execfile() 在全局空间中运行良好。这就是为什么答案通常是“对我来说有效”。

    但是修改被调用脚本的解决方案可能是不可能的。 因此,我在这里报告我认为最好的解决方案,该解决方案是在 exec() 函数的另一个等效问题上发现的(在那篇文章中:https://stackoverflow.com/a/11754346/1808778)。它与 execfile() 的工作原理相同

    def callingFunction(filename)
        # ... 
        d = dict(locals(), **globals())
        execfile(filename, d, d )
    

    该解决方案的优点是我们不需要知道被调用的脚本:它是在 if name == ma​​in 中命名的函数em> 被执行。

    【讨论】:

      【解决方案3】:

      自发布以来,您已经聪明了 3 年 8 个月,所以我假设您已经解决了第一个问题,但鉴于尚未发布解决方案(主要是因为似乎没有人对第一个问题),以下是我的解决方案。

      [更新]

      我提供的最后一个解决方案不正确。下面我提供正确的解决方案,并使用我执行的代码详细解释它。

      问题在于 Python 的 execfile() 内置函数。这是该函数在 Python 3.x 中已被弃用的原因之一。

      当您在runme() 中执行execfile() 时,对象spam()eggs() 被加载到方法runme() 的命名空间中,而不是全局命名空间中(理想情况下应该如此) 。考虑以下代码:

      myscript.py

      def spam():
          print 'spam'
      
      def eggs():
          if 'spam' not in globals():
              print 'method spam() is not present in global namespace'
          spam()
      
      try:
          eggs()
      except Exception as e:
          print e
      

      mainprogram.py

      class mainprogram():
          def runme(self):
              execfile("myscript.py")
              print 'Objects lying in local namespace of runme() are -'
              print locals()
      
      this = mainprogram()
      this.runme()
      

      解释器输出

      >>>import mainprogram
      method spam() is not present in global namespace
      name 'spam' is not defined
      Objects lying in local namespace of runme() are -
      {'e': NameError("name 'spam' is not defined",), 'spam': <function spam at 0x000000000000002B>, 'eggs': <function eggs at 0x000000000000002C>, 'self': <mainprogram.mainprogram instance at 0x000000000000002D>}
      

      从输出中你可以看到spam() 不在全局命名空间中,而是在方法runme() 的命名空间中。所以假设,调用spam() 的正确方法是

      def eggs():
          global this
          this.runme.spam()
      

      但是,当 spam() 位于 runme() 的命名空间内时,无法访问它。因此,解决方案是在全局命名空间中插入spam(),如下所示:

      myscript.py

      global spam
      def spam():
          print "spam"
      
      def eggs():
          spam()
      
      eggs()
      

      这将确保在 globals() 字典(即全局命名空间)内创建对对象 spam() 的引用,使其可从 eggs() 调用。

      【讨论】:

        【解决方案4】:

        您确定您发布了您遇到问题的实际代码吗?第一个脚本对我来说很好。

        第二个错误是意料之中的:名称“bleh”没有定义在外部块中,只在“mainprogram”的命名空间中

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-27
          • 2012-11-26
          • 2011-04-02
          • 2017-12-24
          • 1970-01-01
          • 2019-12-17
          • 2015-09-22
          • 1970-01-01
          相关资源
          最近更新 更多