简体   繁体   English

在python中使用execfile的NameError

[英]NameError using execfile in python

My application has a button to execute a python script dynamically using execfile . 我的应用程序有一个按钮,使用execfile动态执行python脚本。 If I define a function inside the script (eg. spam() ) and try to use that function inside another function (eg. eggs() ), I get this error: 如果我在脚本中定义一个函数(例如spam() )并尝试在另一个函数中使用该函数(例如eggs() ),我会收到此错误:

NameError: global name 'spam' is not defined

What is the correct way to call the spam() function from within eggs() ? 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()

Also, I can't seem to be able to execute a method from my main application in the script. 此外,我似乎无法从脚本中的主应用程序执行方法。 ie

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

 #my2ndscript.py
 bleh()

The error is: 错误是:

NameError: name 'bleh' is not defined

What is the correct way to call bleh() from my2ndscript.py ? my2ndscript.py调用bleh()的正确方法是什么?

EDIT : Updated first issue 编辑 :更新了第一期

You're 3 years 8 months wiser since you posted so I'm assuming you'd have figured the first issue out, but given that a solution has not yet been posted (primarily because no one seemed to have a problem with the first issue), the following is my solution. 自从你发布以来,你已经3年8个月了,所以我假设你已经想出了第一个问题,但考虑到尚未发布解决方案(主要是因为第一个问题似乎没有人出现问题) ),以下是我的解决方案。

[UPDATED] [更新]

The last solution I provided was incorrect. 我提供的最后一个解决方案不正确。 Below I am providing the correct solution and explaining it in detail using code that I executed. 下面我提供正确的解决方案,并使用我执行的代码详细解释它。

The problem is inherent in Python's execfile() builtin. 这个问题是Python内置的execfile()所固有的。 Its one of the reasons that function has been deprecated in Python 3.x. 它是Python 3.x中不推荐使用该函数的原因之一。

When you executed execfile() inside runme() , the objects spam() and eggs() were loaded into method runme() 's namespace, and not into the global namespace (as they should ideally be) . 当你在runme()执行execfile() ,对象spam()eggs()被加载到方法runme()的命名空间中,而不是加载到全局命名空间中(理想情况下应该如此) Consider the following code: 请考虑以下代码:

myscript.py 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 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()

Interpreter Output 口译员输出

>>>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>}

From the output you can see that spam() is not in the global namespace, but in method runme() 's namespace. 从输出中可以看到spam()不在全局命名空间中,而是在方法runme()的命名空间中。 So hypothetically, the correct way to call spam() would have been 所以假设,调用spam()的正确方法就是这样

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

However, there is no way to access spam() while it is lying inside runme() 's namespace. 但是,当它位于runme()的命名空间内时,无法访问spam() The solution, therefore, is to insert spam() in the global namespace as follows: 因此,解决方案是在全局命名空间中插入spam() ,如下所示:

myscript.py myscript.py

global spam
def spam():
    print "spam"

def eggs():
    spam()

eggs()

This will ensure that a reference to object spam() is created inside the globals() dictionary (ie, the global namespace), making it callable from eggs() . 这将确保在globals()字典(即全局命名空间)中创建对object spam()的引用,使其可以从eggs()调用。

Addy689 explained the real problem: it is when calling execfile() from a function that it appears. Addy689解释了真正的问题:它是它出现的函数调用execfile()时。 execfile() works well from the global space. execfile()在全局空间中运行良好。 That's why answers are often 'for me it works'. 这就是为什么答案往往“对我来说有效”。

But the solution to modify the called scripts may not be possible. 但是修改被调用脚本的解决方案可能无法实现。 So I report here the solution I think the best one, found on another equivalent problem with the exec() function (in that post: https://stackoverflow.com/a/11754346/1808778 ). 所以我在这里报告我认为最好的解决方案,在exec()函数的另一个等效问题上找到(在该帖子中: https//stackoverflow.com/a/11754346/1808778 )。 It works the same with execfile() 它与execfile()的工作方式相同

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

Advantage of that solution is that we don't need to know the called script: it is the function nammed in if name == main that is executed. 该解决方案的优点是我们不需要知道被调用的脚本: 如果执行了name == main ,则该函数被命名为nammed。

In the second case you will need import (not sure whether "mainprogram.py" is on your $PYTHONPATH ) 在第二种情况下,你需要import (不确定你的$PYTHONPATH上是否有“mainprogram.py”)

#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()

but this will create a second instance of mainprogram . 但这将创建mainprogram的第二个实例。 Or, better yet: 或者,更好的是:

#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()

I guess that execfile is not the right solution for your problem anyway. 我想execfile无论如何都不是你问题的正确解决方案。 Why don't you use import or __import__ (and reload() in case the script changes between those clicks)? 为什么不使用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()

Are you sure you posted the actual code you are having trouble with? 您确定发布了遇到问题的实际代码吗? The first script works fine for me. 第一个脚本对我来说很好。

The second error is to be expected: the name "bleh" is not defined in the outer block, only within the namespace of "mainprogram" 第二个错误是预期的:名称“bleh”没有在外部块中定义,只在“mainprogram”的命名空间内定义

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM