3

我有一个 Python 应用程序。它通过执行以下操作加载配置文件(和各种其他文件):

_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = os.path.join(_path, 'conf')

这工作正常。但是,当我用 py2exe 打包应用程序时,会发生不好的事情:

  File "proj\config.pyc", line 8, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\
\dist\\library.zip\\conf'

显然,这是一条无效的路径......有什么更强大的方法来做到这一点?我不想在程序中指定绝对路径,因为它可以放在不同的文件夹中。我应该说“如果它说文件夹名称是'library.zip',那么再往下走一层到'dist'文件夹”?

请注意,我有非常嵌套的目录层次结构......例如,我有一个模块 gui.utils.images,存储在“gui/utils/images.py”中,它使用它的路径来访问“gui/images/ok. png”,例如。现在 py2exe 版本会尝试访问“proj/dist/library.zip/gui/images/ok.png”或其他东西,但这是行不通的。

4

5 回答 5

10

做这种事情的通常方法(如果我理解正确的话)是这样的:

  1. 检查 sys.frozen,py2exe 试图设置它,使用 getattr(sys, 'frozen', '')
  2. 如果未设置,请使用通常的方法,因为您是从源代码运行的
  3. 如果已设置,请检查 sys.executable ,因为这将指向 .exe 所在的位置(而不是 python.exe 所在的位置,这是它通常指向的位置)。使用 os.path.dirname(sys.executable) 之类的东西,然后将其与您的相对路径连接以查找子文件夹等

例子:

frozen = getattr(sys, 'frozen', '')

if not frozen:
    # not frozen: in regular python interpreter
    approot = os.path.dirname(__file__)

elif frozen in ('dll', 'console_exe', 'windows_exe'):
    # py2exe:
    approot = os.path.dirname(sys.executable)

elif frozen in ('macosx_app',):
    # py2app:
    # Notes on how to find stuff on MAC, by an expert (Bob Ippolito):
    # http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html
    approot = os.environ['RESOURCEPATH']

或者它的一些变体......后者处理py2app的使用。如果需要,您可以将其扩展到其他构建器。

于 2009-12-04T03:20:38.033 回答
2

您如何看待对所有包含的文件使用相对路径?我想应该可以将sys.path.append(".." + os.path.sep + "images")关于 ok.png 的示例用于您的示例,然后您就可以使用open("ok.png", "rb"). 使用相对路径应该可以解决由 py2exe 生成的 library.zip 文件的问题,至少这对我来说是这样。

于 2009-10-02T20:08:48.967 回答
2

从 py2exe 应用程序中使用 os.path.dirname(os.path.abspath(sys.argv[0])) ,它将以与 python 脚本相同的方式工作(因此您无需每次都创建 exe 即可进行测试)和从exe。

这比使用相对路径要好得多,因为您不必担心应用程序(.py 或 .exe)从何处运行。

于 2010-05-18T18:32:24.307 回答
2

这是我的解决方案(在 Windows、Linux 和 Mac 上测试)。如果应用程序或 Python 脚本通过符号链接启动,它也可以工作。

# Get if frozen
is_frozen = bool( getattr(sys, 'frozen', None) )

# Get path variable
path = sys.path if is_frozen else sys.argv

# Get nonempty first element or raise error
if path and path[0]:
    apppath = path[0]
elif is_frozen():
    raise RuntimeError('Cannot determine app path because sys.path[0] is empty.')
else:
    raise RuntimeError('Cannot determine app path in interpreter mode.')

# Make absolute (eliminate symbolic links)
apppath = os.path.abspath( os.path.realpath(apppath) )

# Split and return
appdir, appname = os.path.split(apppath)
于 2012-04-15T13:12:55.370 回答
0

我在 Windows 中使用以下技巧。
当程序被冻结在 py2exe“可执行文件”(即my_application.exe)中时,dirname(__file__)返回运行您的主要 python 脚本的文件夹。奇怪的是,该文件夹不是包含my_application.exe的文件夹,而是my_application.exe本身。
请注意,my_application.exe不是二进制文件,而是一个压缩文件夹(您可以将其解压缩),其中包含 python 库和您编译的脚本。
这就是为什么os.path.dirname__file__的实际上是 my_application.exe

因此,此代码为您提供了配置文件或图像的根目录(如果应用程序冻结,则为包含 py2exe 可执行文件的文件夹,否则为运行 python 脚本的文件夹):

dirname = os.path.dirname(__file__)
if dirname.endswith('.exe'):
    dirname = os.path.split(dirname)[0]

显然,您可以使用更通用、可移植的方法来检测文件是否被冻结,因为其他答案显示而不是该endswith方法。

于 2014-08-27T01:25:49.410 回答