在我的脚本之前制作 Python 运行 几行
Making Python run a few lines before my script
我需要 运行 脚本 foo.py
,但我还需要在 foo.py
中的代码之前向 运行 插入一些调试行。目前我只是将这些行放在 foo.py
中,我很小心不要将其提交给 Git,但我不喜欢这个解决方案。
我想要的是一个单独的文件 bar.py
,我不承诺 Git。那我要运行:
python /somewhere/bar.py /somewhere_else/foo.py
我想要做的是首先 运行 bar.py
中的一些代码行,然后 运行 foo.py
作为 __main__
。它应该与 bar.py
行 运行 在同一个进程中,否则调试行将无济于事。
有没有办法让 bar.py
做到这一点?
有人建议:
import imp
import sys
# Debugging code here
fp, pathname, description = imp.find_module(sys.argv[1])
imp.load_module('__main__', fp, pathname, description)
问题在于,因为它使用进口机器,所以我需要与 foo.py
到 运行 位于同一文件夹中。我不想要那个。我想简单地输入 foo.py
.
的完整路径
另外:该解决方案也需要与 .pyc
文件一起使用。
foo.py
不必与主文件夹位于同一文件夹中。使用
export PYTHONPATH=$HOME/dirWithFoo/:$PYTHONPATH
将foo
所在的路径添加到Python路径。现在你可以
from foo import myfunc
myfunc()
让 myfunc 做任何你想做的事
您可能有以下内容:
if __name__ == '__main__':
# some code
相反,在 foo
中的函数 main()
中编写代码,然后执行:
if __name__ == '__main__':
main()
然后,在 bar 中,您可以导入 foo 并调用 foo.main()
。
此外,如果您需要change the working directory,您可以使用os.chdir(path)
方法,例如os.chdir('path/of/bar')
.
如果文件是 .pyc
,您可以使用 execfile()
if the file is .py
and uncompyle2。
假设您的文件结构如下:
test|-- foo.py
|-- bar
|--bar.py
foo.py
import sys
a = 1
print ('debugging...')
# run the other file
if sys.argv[1].endswith('.py'): # if .py run right away
execfile(sys.argv[1], globals(), locals())
elif sys.argv[1].endswith('.pyc'): # if .pyc, first uncompyle, then run
import uncompyle2
from StringIO import StringIO
f = StringIO()
uncompyle2.uncompyle_file(sys.argv[1], f)
f.seek(0)
exec(f.read(), globals(), locals())
bar.py
print a
print 'real job'
并且在 test/
中,如果您这样做:
$ python foo.py bar/bar.py
$ python foo.py bar/bar.pyc
两者,输出相同:
debugging...
1
real job
另请参阅此 。
你试过吗?
bar.py
imp.load_source('__main__', '../../foo.py')
对我来说,它运行 foo.py 中的任何内容(在 main 之前和内部)
之后,也许你在 bar.py 中做的事情可能比我的基本测试更棘手。
load_source 的好处是,如果 .pyc 已经存在,它会导入它,或者启动 .py 的 "compile",然后导入 .pyc。
bar.py
必须表现得像 Python 解释器本身,而 运行 foo.py
(或 foo.pyc
,正如你所要求的那样)就好像这是主要脚本。这出奇的难。我 90% 的解决方案如下所示:
def run_script_as_main(cmdline):
# It is crucial to import locally what we need as we
# later remove everything from __main__
import sys, imp, traceback, os
# Patch sys.argv
sys.argv = cmdline
# Clear the __main__ namespace and set it up to run
# the secondary program
maindict = sys.modules["__main__"].__dict__
builtins = maindict['__builtins__']
maindict.clear()
maindict['__file__'] = cmdline[0]
maindict['__builtins__'] = builtins
maindict['__name__'] = "__main__"
maindict['__doc__'] = None
# Python prepends a script's location to sys.path
sys.path[0] = os.path.dirname(os.path.abspath(cmdline[0]))
# Treat everything as a Python source file, except it
# ends in '.pyc'
loader = imp.load_source
if maindict["__file__"].endswith(".pyc"):
loader = imp.load_compiled
with open(cmdline[0], 'rb') as f:
try:
loader('__main__', maindict["__file__"], f)
except Exception:
# In case of an exception, remove this script from the
# stack trace; if you don't care seeing some bar.py in
# traceback, you can leave that out.
ex_type, ex_value, ex_traceback = sys.exc_info()
tb = traceback.extract_tb(ex_traceback, None)[1:]
sys.stderr.write("Traceback (most recent call last):\n")
for line in traceback.format_list(tb):
sys.stderr.write(line)
for line in traceback.format_exception_only(ex_type, ex_value):
sys.stderr.write(line)
这模仿了 Python 解释器的默认行为
比较紧密。它设置系统全局变量 __name__
、__file__
、
sys.argv
,将脚本位置插入 sys.path
,清除全局命名空间等
您可以将该代码复制到 bar.py
或从某处导入它并像这样使用它:
if __name__ == "__main__":
# You debugging setup goes here
...
# Run the Python program given as argv[1]
run_script_as_main(sys.argv[1:])
然后,鉴于此:
$ find so-foo-bar
so-foo-bar
so-foo-bar/debugaid
so-foo-bar/debugaid/bar.py
so-foo-bar/foo.py
和 foo.py
看起来像这样:
import sys
if __name__ == "__main__":
print "My name is", __name__
print "My file is", __file__
print "My command line is", sys.argv
print "First 2 path items", sys.path[:2]
print "Globals", globals().keys()
raise Exception("foo")
... 运行ning foo.py
通过 bar.py
给你:
$ python so-foo-bar/debugaid/bar.py so-foo-bar/foo.py
My name is __main__
My file is so-foo-bar/foo.py
My command line is ['so-foo-bar/foo.py']
First 2 path items ['~/so-foo-bar', '/usr/local/...']
Globals ['__builtins__', '__name__', '__file__', 'sys', '__package__', '__doc__']
Traceback (most recent call last):
File "so-foo-bar/foo.py", line 9, in
raise Exception("foo")
Exception: foo
虽然我猜测 run_script_as_main
缺少一些有趣的细节,但它与 Python 的方式非常接近 运行 foo.py
.
这个解决方案最终对我很有效:
#!/usr/bin/env python
import imp
import sys
import os.path
file_path = sys.argv.pop(1)
assert os.path.exists(file_path)
folder, file_name = os.path.split(file_path)
###############################################################################
# #
# Debugging cruft here
# #
###############################################################################
module_name, _ = os.path.splitext(file_name)
sys.path.append(folder)
imp.load_module('__main__', *imp.find_module(module_name))
Python 有一种在启动时 运行ning 代码的机制; site 模块。
"This module is automatically imported during initialization."
站点模块将尝试在导入 __main__
之前导入名为 sitecustomize
的模块。
如果您的环境指示它,它还将尝试导入名为 usercustomize
的模块。
例如,您可以将 sitecustomize.py 文件放入包含以下内容的站点包文件夹中:
import imp
import os
if 'MY_STARTUP_FILE' in os.environ:
try:
file_path = os.environ['MY_STARTUP_FILE']
folder, file_name = os.path.split(file_path)
module_name, _ = os.path.splitext(file_name)
fp, pathname, description = imp.find_module(module_name, [folder])
except Exception as e:
# Broad exception handling since sitecustomize exceptions are ignored
print "There was a problem finding startup file", file_path
print repr(e)
exit()
try:
imp.load_module(module_name, fp, pathname, description)
except Exception as e:
print "There was a problem loading startup file: ", file_path
print repr(e)
exit()
finally:
# "the caller is responsible for closing the file argument" from imp docs
if fp:
fp.close()
然后你可以 运行 你的脚本是这样的:
MY_STARTUP_FILE=/somewhere/bar.py python /somewhere_else/foo.py
- 您可以 运行 foo.py 之前的任何脚本,而无需添加代码来重新导入
__main__
。
- 运行
export MY_STARTUP_FILE=/somewhere/bar.py
不需要每次都引用
我需要 运行 脚本 foo.py
,但我还需要在 foo.py
中的代码之前向 运行 插入一些调试行。目前我只是将这些行放在 foo.py
中,我很小心不要将其提交给 Git,但我不喜欢这个解决方案。
我想要的是一个单独的文件 bar.py
,我不承诺 Git。那我要运行:
python /somewhere/bar.py /somewhere_else/foo.py
我想要做的是首先 运行 bar.py
中的一些代码行,然后 运行 foo.py
作为 __main__
。它应该与 bar.py
行 运行 在同一个进程中,否则调试行将无济于事。
有没有办法让 bar.py
做到这一点?
有人建议:
import imp
import sys
# Debugging code here
fp, pathname, description = imp.find_module(sys.argv[1])
imp.load_module('__main__', fp, pathname, description)
问题在于,因为它使用进口机器,所以我需要与 foo.py
到 运行 位于同一文件夹中。我不想要那个。我想简单地输入 foo.py
.
另外:该解决方案也需要与 .pyc
文件一起使用。
foo.py
不必与主文件夹位于同一文件夹中。使用
export PYTHONPATH=$HOME/dirWithFoo/:$PYTHONPATH
将foo
所在的路径添加到Python路径。现在你可以
from foo import myfunc
myfunc()
让 myfunc 做任何你想做的事
您可能有以下内容:
if __name__ == '__main__':
# some code
相反,在 foo
中的函数 main()
中编写代码,然后执行:
if __name__ == '__main__':
main()
然后,在 bar 中,您可以导入 foo 并调用 foo.main()
。
此外,如果您需要change the working directory,您可以使用os.chdir(path)
方法,例如os.chdir('path/of/bar')
.
如果文件是 .pyc
,您可以使用 execfile()
if the file is .py
and uncompyle2。
假设您的文件结构如下:
test|-- foo.py
|-- bar
|--bar.py
foo.py
import sys
a = 1
print ('debugging...')
# run the other file
if sys.argv[1].endswith('.py'): # if .py run right away
execfile(sys.argv[1], globals(), locals())
elif sys.argv[1].endswith('.pyc'): # if .pyc, first uncompyle, then run
import uncompyle2
from StringIO import StringIO
f = StringIO()
uncompyle2.uncompyle_file(sys.argv[1], f)
f.seek(0)
exec(f.read(), globals(), locals())
bar.py
print a
print 'real job'
并且在 test/
中,如果您这样做:
$ python foo.py bar/bar.py
$ python foo.py bar/bar.pyc
两者,输出相同:
debugging...
1
real job
另请参阅此
你试过吗?
bar.py
imp.load_source('__main__', '../../foo.py')
对我来说,它运行 foo.py 中的任何内容(在 main 之前和内部)
之后,也许你在 bar.py 中做的事情可能比我的基本测试更棘手。
load_source 的好处是,如果 .pyc 已经存在,它会导入它,或者启动 .py 的 "compile",然后导入 .pyc。
bar.py
必须表现得像 Python 解释器本身,而 运行 foo.py
(或 foo.pyc
,正如你所要求的那样)就好像这是主要脚本。这出奇的难。我 90% 的解决方案如下所示:
def run_script_as_main(cmdline):
# It is crucial to import locally what we need as we
# later remove everything from __main__
import sys, imp, traceback, os
# Patch sys.argv
sys.argv = cmdline
# Clear the __main__ namespace and set it up to run
# the secondary program
maindict = sys.modules["__main__"].__dict__
builtins = maindict['__builtins__']
maindict.clear()
maindict['__file__'] = cmdline[0]
maindict['__builtins__'] = builtins
maindict['__name__'] = "__main__"
maindict['__doc__'] = None
# Python prepends a script's location to sys.path
sys.path[0] = os.path.dirname(os.path.abspath(cmdline[0]))
# Treat everything as a Python source file, except it
# ends in '.pyc'
loader = imp.load_source
if maindict["__file__"].endswith(".pyc"):
loader = imp.load_compiled
with open(cmdline[0], 'rb') as f:
try:
loader('__main__', maindict["__file__"], f)
except Exception:
# In case of an exception, remove this script from the
# stack trace; if you don't care seeing some bar.py in
# traceback, you can leave that out.
ex_type, ex_value, ex_traceback = sys.exc_info()
tb = traceback.extract_tb(ex_traceback, None)[1:]
sys.stderr.write("Traceback (most recent call last):\n")
for line in traceback.format_list(tb):
sys.stderr.write(line)
for line in traceback.format_exception_only(ex_type, ex_value):
sys.stderr.write(line)
这模仿了 Python 解释器的默认行为
比较紧密。它设置系统全局变量 __name__
、__file__
、
sys.argv
,将脚本位置插入 sys.path
,清除全局命名空间等
您可以将该代码复制到 bar.py
或从某处导入它并像这样使用它:
if __name__ == "__main__":
# You debugging setup goes here
...
# Run the Python program given as argv[1]
run_script_as_main(sys.argv[1:])
然后,鉴于此:
$ find so-foo-bar
so-foo-bar
so-foo-bar/debugaid
so-foo-bar/debugaid/bar.py
so-foo-bar/foo.py
和 foo.py
看起来像这样:
import sys
if __name__ == "__main__":
print "My name is", __name__
print "My file is", __file__
print "My command line is", sys.argv
print "First 2 path items", sys.path[:2]
print "Globals", globals().keys()
raise Exception("foo")
... 运行ning foo.py
通过 bar.py
给你:
$ python so-foo-bar/debugaid/bar.py so-foo-bar/foo.py My name is __main__ My file is so-foo-bar/foo.py My command line is ['so-foo-bar/foo.py'] First 2 path items ['~/so-foo-bar', '/usr/local/...'] Globals ['__builtins__', '__name__', '__file__', 'sys', '__package__', '__doc__'] Traceback (most recent call last): File "so-foo-bar/foo.py", line 9, in raise Exception("foo") Exception: foo
虽然我猜测 run_script_as_main
缺少一些有趣的细节,但它与 Python 的方式非常接近 运行 foo.py
.
这个解决方案最终对我很有效:
#!/usr/bin/env python
import imp
import sys
import os.path
file_path = sys.argv.pop(1)
assert os.path.exists(file_path)
folder, file_name = os.path.split(file_path)
###############################################################################
# #
# Debugging cruft here
# #
###############################################################################
module_name, _ = os.path.splitext(file_name)
sys.path.append(folder)
imp.load_module('__main__', *imp.find_module(module_name))
Python 有一种在启动时 运行ning 代码的机制; site 模块。
"This module is automatically imported during initialization."
站点模块将尝试在导入 __main__
之前导入名为 sitecustomize
的模块。
如果您的环境指示它,它还将尝试导入名为 usercustomize
的模块。
例如,您可以将 sitecustomize.py 文件放入包含以下内容的站点包文件夹中:
import imp
import os
if 'MY_STARTUP_FILE' in os.environ:
try:
file_path = os.environ['MY_STARTUP_FILE']
folder, file_name = os.path.split(file_path)
module_name, _ = os.path.splitext(file_name)
fp, pathname, description = imp.find_module(module_name, [folder])
except Exception as e:
# Broad exception handling since sitecustomize exceptions are ignored
print "There was a problem finding startup file", file_path
print repr(e)
exit()
try:
imp.load_module(module_name, fp, pathname, description)
except Exception as e:
print "There was a problem loading startup file: ", file_path
print repr(e)
exit()
finally:
# "the caller is responsible for closing the file argument" from imp docs
if fp:
fp.close()
然后你可以 运行 你的脚本是这样的:
MY_STARTUP_FILE=/somewhere/bar.py python /somewhere_else/foo.py
- 您可以 运行 foo.py 之前的任何脚本,而无需添加代码来重新导入
__main__
。 - 运行
export MY_STARTUP_FILE=/somewhere/bar.py
不需要每次都引用