如何在py2exe中获取可执行文件的当前目录?

20 投票
4 回答
22642 浏览
提问于 2025-04-15 19:27

我在我的脚本中使用了一段代码,目的是跨平台地确定脚本的运行位置:

SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

这段代码很简单。接下来,我会在脚本的其他地方使用 SCRIPT_ROOT,以确保所有路径都是相对的。我的问题出现在我通过 py2exe 运行它的时候,因为生成的可执行文件没有设置 __file__,所以我的脚本就出错了。有没有人知道怎么解决或者绕过这个问题?

4 个回答

3

试试这个:

import os
import sys
os.path.realpath(os.path.dirname(sys.argv[0]))
9

Py2exe并没有定义__file__这个东西:http://www.py2exe.org/index.cgi/Py2exeEnvironment

提问者想要一个适合py2exe的版本:

SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

最好的办法是判断Python程序是否被打包成了exe文件,py2exe有相关的文档说明这个问题:http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe

import imp, os, sys

def main_is_frozen():
   return (hasattr(sys, "frozen") or # new py2exe
           hasattr(sys, "importers") # old py2exe
           or imp.is_frozen("__main__")) # tools/freeze

def get_main_dir():
   if main_is_frozen():
       return os.path.dirname(sys.executable)
   return os.path.dirname(os.path.realpath(__file__))

SCRIPT_ROOT = get_main_dir()

因为Python是EAFP的,所以这里有一个EAFP版本...

try:
   if sys.frozen or sys.importers:
      SCRIPT_ROOT = os.path.dirname(sys.executable)
except AttributeError:
   SCRIPT_ROOT = os.path.dirname(os.path.realpath(__file__))

谢谢!

27

这里是py2exe的文档参考,以下是一些相关内容:

  • sys.executable 是指exe文件的完整路径。
  • sys.argv 的第一个项目是可执行文件的完整路径,后面的都是命令行参数。
  • sys.frozen 只在可执行文件中存在。对于控制台可执行文件,它的值是“console_exe”;对于没有控制台的图形界面可执行文件,它的值是“windows_exe”;对于进程内的dll服务器,它的值是“dll”。
  • __file__ 是没有定义的(你可能想用 sys.argv[0] 来代替)。

从这些文档中并不清楚“exe文件”和“可执行文件”是否是同一个东西,因此也不确定 sys.executablesys.argv[0] 是否是一样的。根据我之前处理过的代码,它同时适用于 script.py 和 py2exe_executable.exe,我发现了类似这样的内容:

if hasattr(sys, 'frozen'):
    basis = sys.executable
else:
    basis = sys.argv[0]
required_folder = os.path.split(basis)[0]

如我所说,这段代码是有效的,但我不记得当时为什么觉得这样做是必要的,而不是直接使用 sys.argv[0]

仅使用 basis 就足够完成当前的任务(读取该目录下的文件)。为了更永久的记录,可以分开处理像 os.path.realpath(basis) 这样的内容。

更新 实际上做了一个测试;这比猜测和空谈要好得多 :-)

总结:忽略 sys.frozen,忽略 sys.executable,毫无条件使用 sys.argv[0]。

证据:

=== foo.py ===

# coding: ascii
import sys, os.path
print 'sys has frozen:', hasattr(sys, 'frozen')
print 'using sys.executable:', repr(os.path.dirname(os.path.realpath(sys.executable)))
print 'using sys.argv[0]:',    repr(os.path.dirname(os.path.realpath(sys.argv[0]   )))

=== setup.py ===

from distutils.core import setup
import py2exe
setup(console=['foo.py'])

=== 结果 ===

C:\junk\so\py2exe>\python26\python foo.py
sys has frozen: False
using sys.executable: 'C:\\python26'
using sys.argv[0]: 'C:\\junk\\so\\py2exe' # where foo.py lives

C:\junk\so\py2exe>dist\foo
sys has frozen: True
using sys.executable: 'C:\\junk\\so\\py2exe\\dist'
using sys.argv[0]: 'C:\\junk\\so\\py2exe\\dist' # where foo.exe lives

撰写回答