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

2024-11-29 08:42:00
admin
原创
168
摘要:问题描述:我想看看在 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)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用