如何正确确定当前脚本目录?[重复]

2024-11-29 08:42:00
admin
原创
123
摘要:问题描述:我想看看在 Python 中确定当前脚本目录的最佳方法是什么。我发现,由于调用 Python 代码的方式很多,很难找到一个好的解决方案。这里存在一些问题:__file__如果使用 执行脚本则未定义exec,execfile__module__仅在模块中定义使用案例:./myfile.pypython...

问题描述:

我想看看在 Python 中确定当前脚本目录的最佳方法是什么。

我发现,由于调用 Python 代码的方式很多,很难找到一个好的解决方案。

这里存在一些问题:

  • __file__如果使用 执行脚本则未定义execexecfile

  • __module__仅在模块中定义

使用案例:

  • ./myfile.py

  • python myfile.py

  • ./somedir/myfile.py

  • python somedir/myfile.py

  • execfile('myfile.py')(来自另一个脚本,该脚本可以位于另一个目录中,并且可以有另一个当前目录。

我知道没有完美的解决方案,但我正在寻找解决大多数情况的最佳方法。

最常用的方法是,os.path.dirname(os.path.abspath(__file__))但如果您使用从另一个脚本执行脚本,这实际上不起作用exec()

警告

任何使用当前目录的解决方案都将失败,这可能根据脚本的调用方式而有所不同,也可以在正在运行的脚本中进行更改。


解决方案 1:

os.path.dirname(os.path.abspath(__file__))

确实是你能得到的最好的结果。

使用exec/执行脚本并不常见execfile;通常您应该使用模块基础结构来加载脚本。如果您必须使用这些方法,我建议您__file__globals传递给脚本的 中进行设置,以便它可以读取该文件名。

没有其他方法可以在执行的代码中获取文件名:正如您注意到的,CWD 可能位于完全不同的地方。

解决方案 2:

如果您确实想涵盖通过 调用脚本的情况execfile(...),则可以使用inspect模块推断文件名(包括路径)。据我所知,这适用于您列出的所有情况:

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

解决方案 3:

在 Python 3.4+ 中,你可以使用更简单的pathlib模块:

from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent

您还可以使用__file__(当可用时)来inspect完全避免使用该模块:

from pathlib import Path
parent = Path(__file__).resolve().parent

解决方案 4:

#!/usr/bin/env python
import inspect
import os
import sys

def get_script_dir(follow_symlinks=True):
    if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
        path = os.path.abspath(sys.executable)
    else:
        path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        path = os.path.realpath(path)
    return os.path.dirname(path)

print(get_script_dir())

execfile()它适用于 CPython、Jython、Pypy。如果使用(sys.argv[0]__file__- 解决方案在此处会失败)执行脚本,则它可以工作。如果脚本位于可执行 zip 文件 (/an egg)中,则它可以工作。如果脚本是PYTHONPATH=/path/to/library.zip python -mscript_to_run从 zip 文件“导入”( ) 的,则它可以工作;在这种情况下,它会返回存档路径。如果脚本被编译为独立可执行文件 ( sys.frozen),则它可以工作。它适用于符号链接 (realpath消除符号链接)。它在交互式解释器中工作;在这种情况下,它会返回当前工作目录。

解决方案 5:

os.path...方法是 Python 2 中的“已完成的事情”。

在 Python 3 中,你可以按如下方式找到脚本的目录:

from pathlib import Path
script_path = Path(__file__).parent

解决方案 6:

注意:这个答案现在是一个包(也具有安全的相对导入功能)

https://github.com/heetbeet/locate

$ pip install locate

$ python
>>> from locate import this_dir
>>> print(this_dir())
C:/Users/simon

对于.py脚本以及交互式使用:

我经常使用脚本的目录(用于访问与脚本一起存储的文件),但我也经常在交互式 shell 中运行这些脚本以进行调试。我将其定义this_dir为:

  • 运行或导入.py文件时,文件的基本目录。这始终是正确的路径。

  • 运行笔记本时.ipyn,当前工作目录。这始终是正确的路径,因为 Jupyter 将工作目录设置为.ipynb基目录。

  • 在 REPL 中运行时,当前工作目录。嗯,当代码与文件分离时,实际的“正确路径”是什么?相反,在调用 REPL 之前,您有责任更改为“正确路径”。

Python 3.4 (及以上版本):

from pathlib import Path
this_dir = Path(globals().get("__file__", "./_")).absolute().parent

Python 2 (及以上版本):

import os
this_dir = os.path.dirname(os.path.abspath(globals().get("__file__", "./_")))

解释:

  • globals()将所有全局变量作为字典返回。

  • .get("__file__", "./_")`"__file__"如果 中存在 则返回键的值globals(),否则返回提供的默认值"./_"`。

  • 代码的其余部分只是扩展__file__(或"./_")为绝对文件路径,然后返回文件路径的基目录。

选择:

如果你确定__file__周围的代码可以使用,那么你可以简化如下:

  • >=Python 3.4this_dir = Path(__file__).absolute().parent

  • >=Python 2this_dir = os.path.dirname(os.path.abspath(__file__))

解决方案 7:

import os
cwd = os.getcwd()

做你想做的事?我不确定你所说的“当前脚本目录”到底是什么意思。对于你给出的用例,预期的输出是什么?

解决方案 8:

只需使用os.path.dirname(os.path.abspath(__file__))并仔细检查是否真的需要使用这种情况exec。如果您无法将脚本用作模块,则可能是设计存在问题的迹象。

请记住Python 之禅 #8,如果您认为对于某个用例来说,有一个很好的论据证明它必须适用于exec,那么请让我们知道有关问题背景的更多细节。

解决方案 9:

要获取包含当前脚本的目录的绝对路径,您可以使用:

from pathlib import Path
absDir = Path(__file__).parent.resolve()

请注意.resolve()调用是必需的,因为这是使路径绝对化的调用。如果没有resolve(),您将获得类似 的内容'.'

此解决方案使用pathlib,它是自 v3.4 (2014) 以来 Python stdlib 的一部分。与使用 的其他解决方案相比,这是更可取的os

官方pathlib文档有一个有用的表格,将旧os函数映射到新函数:https://docs.python.org/3/library/pathlib.html#correspondence-to-tools-in-the-os-module

解决方案 10:

首先,如果我们讨论注入匿名代码的方法,这里缺少几个用例。

code.compile_command()
code.interact()
imp.load_compiled()
imp.load_dynamic()
imp.load_module()
__builtin__.compile()
loading C compiled shared objects? example: _socket?)

但真正的问题是,你的目标是什么 - 你是想强制执行某种安全措施吗?还是你只是对正在加载的内容感兴趣。

如果您对安全性感兴趣,通过 exec/execfile 导入的文件名无关紧要 - 您应该使用rexec,它提供以下内容:

此模块包含 RExec 类,支持 r_eval()、r_execfile()、r_exec() 和 r_import() 方法,这些方法是标准 Python 函数 eval()、execfile() 以及 exec 和 import 语句的受限版本。在此受限环境中执行的代码只能访问被视为安全的模块和函数;您可以根据需要将 RExec 子类化以添加或删除功能。

然而,如果这更像是一种学术追求......这里有几个愚蠢的方法,你也许可以深入研究一下......

示例脚本:

./deep.py

print ' >> level 1'
execfile('deeper.py')
print ' << level 1'

./deeper.py

print '     >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '     << level 2'

/tmp/deepest.py

print '         >> level 3'
print '             I can see the earths core.'
print '         << level 3'

./codespy.py

import sys, os

def overseer(frame, event, arg):
    print "loaded(%s)" % os.path.abspath(frame.f_code.co_filename)

sys.settrace(overseer)
execfile("deep.py")
sys.exit(0)

输出

loaded(/Users/synthesizerpatel/deep.py)
>> level 1
loaded(/Users/synthesizerpatel/deeper.py)
    >> level 2
loaded(/Users/synthesizerpatel/<string>)
loaded(/tmp/deepest.py)
        >> level 3
            I can see the earths core.
        << level 3
    << level 2
<< level 1

当然,这是一种资源密集型的方法,你需要跟踪所有代码。效率不高。但我认为这是一种新颖的方法,因为即使你深入嵌套,它仍会继续工作。你不能覆盖“eval”。虽然你可以覆盖 execfile()。

请注意,此方法仅涵盖 exec/execfile,而不涵盖“import”。对于更高级别的“模块”加载挂钩,您可能能够使用
sys.path_hooks(由 PyMOTW 提供撰写)。

这就是我所知道的全部内容。

解决方案 11:

这是一个部分解决方案,但仍然比迄今为止发布的所有解决方案都要好。

import sys, os, os.path, inspect

#os.chdir("..")

if '__file__' not in locals():
    __file__ = inspect.getframeinfo(inspect.currentframe())[0]

print os.path.dirname(os.path.abspath(__file__))

现在,所有调用都可以正常工作,但如果有人使用它chdir()来更改当前目录,这也会失败。

笔记:

  • sys.argv[0]不会起作用,-c如果你使用以下命令执行脚本,将会返回python -c "execfile('path-tester.py')"

  • 我在https://gist.github.com/1385555发布了完整的测试,欢迎大家对其进行改进。

解决方案 12:

在大多数情况下这应该有效:

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

解决方案 13:

希望这会有所帮助: - 如果您从任何地方运行脚本/模块,您将能够访问__file__变量,该变量是代表脚本位置的模块变量。

另一方面,如果您正在使用解释器,则您无权访问该变量,您将从中获得一个名称NameError,并且os.getcwd()如果您从其他地方运行该文件,它将为您提供错误的目录。

这个解决方案应该能在所有情况下满足您的需求:

from inspect import getsourcefile
from os.path import abspath
abspath(getsourcefile(lambda:0))

我还没有彻底测试过它,但它解决了我的问题。

解决方案 14:

如果__file__可用:

# -- script1.py --
import os
file_path = os.path.abspath(__file__)
print(os.path.dirname(file_path))

对于那些我们希望能够从解释器运行命令或获取运行脚本的位置的路径:

# -- script2.py --
import os
print(os.path.abspath(''))

这在解释器中是有效的。但是在脚本中运行(或导入)时,它会给出运行脚本的位置的路径,而不是包含打印脚本的目录的路径。

例子:

如果你的目录结构是

test_dir (in the home dir)
├── main.py
└── test_subdir
    ├── script1.py
    └── script2.py

# -- main.py --
import script1.py
import script2.py

输出为:

~/test_dir/test_subdir
~/test_dir

解决方案 15:

由于之前的答案要求您导入一些模块,因此我想我会写一个不需要的答案。如果您不想导入任何内容,请使用下面的代码。

this_dir = '/'.join(__file__.split('/')[:-1])
print(this_dir)

如果脚本已打开/path/to/script.py,则将打印/path/to。请注意,这将在终端上抛出错误,因为没有执行任何文件。这基本上会解析目录,从而__file__删除其最后一部分。在本例中,/script.py删除 以产生输出/path/to

解决方案 16:

print(__import__("pathlib").Path(__file__).parent)
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1056  
  在项目管理的各个阶段中,CDCP(概念设计到商业化生产)阶段尤为关键,它不仅是产品从概念到市场落地的桥梁,也是创新与风险控制的博弈场。创新是推动项目成功的核心动力,而风险控制则是确保项目稳健前行的基石。如何在CDCP阶段平衡这两者,是每个项目管理者和团队必须面对的挑战。创新往往伴随着不确定性,而风险控制则强调对不确定性...
华为IPD流程   1  
  华为的集成产品开发(IPD)流程是业界公认的高效产品开发方法论,旨在通过结构化、系统化的方式提升产品开发的效率和质量。然而,随着市场需求的快速变化,传统的IPD流程也面临着如何快速响应市场、缩短开发周期、提高灵活性的挑战。为了应对这些挑战,华为在IPD流程的基础上进行了持续的优化和创新,使其能够更好地适应快速变化的市场...
华为IPD流程   0  
  华为作为全球领先的通信技术公司,其成功不仅依赖于技术创新,更得益于其科学的管理体系。其中,集成产品开发(IPD)模式是华为产品开发流程的核心,而技术评审与质量保障机制则是IPD中确保产品成功的关键环节。通过系统化的技术评审和严格的质量保障措施,华为能够在产品开发的每个阶段有效识别并解决潜在问题,从而减少返工、提高效率,...
IPD测试流程   0  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为导向、跨职能团队协作的产品开发管理模式。它强调在产品开发的早期阶段就整合市场、研发、制造、供应链等多个部门的资源和能力,从而缩短开发周期、降低成本并提高产品质量。IPD的成功实施依赖于多个关键因素,这些因素不仅决定了开...
华为IPD流程   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用