Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何正确确定当前脚本目录?_Python_Pythonpath_Dirname - Fatal编程技术网

Python 如何正确确定当前脚本目录?

Python 如何正确确定当前脚本目录?,python,pythonpath,dirname,Python,Pythonpath,Dirname,我想看看在Python中确定当前脚本目录的最佳方法是什么 我发现,由于调用Python代码的方法很多,很难找到好的解决方案 以下是一些问题: 如果脚本是使用exec,execfile执行的,则不定义\uuuuuuuu文件 \uuuuu模块仅在模块中定义 用例: /myfile.py python myfile.py /somedir/myfile.py python somedir/myfile.py execfile('myfile.py')(来自另一个脚本,可以位于另一个目录中,也可以

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

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

以下是一些问题:

  • 如果脚本是使用
    exec
    execfile
    执行的,则不定义
    \uuuuuuuu文件
  • \uuuuu模块
    仅在模块中定义
用例:

  • /myfile.py
  • python myfile.py
  • /somedir/myfile.py
  • python somedir/myfile.py
  • execfile('myfile.py')
    (来自另一个脚本,可以位于另一个目录中,也可以具有另一个当前目录
我知道没有完美的解决方案,但我正在寻找解决大多数情况的最佳方法

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

警告 任何使用当前目录的解决方案都将失败,这可能与调用脚本的方式不同,也可能在正在运行的脚本中更改

import os
cwd = os.getcwd()
做你想做的事?我不确定你所说的“当前脚本目录”到底是什么意思。你给出的用例的预期输出是什么

os.path.dirname(os.path.abspath(__file__))
确实是你能得到的最好的

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


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

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

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

只需使用
os.path.dirname(os.path.abspath(_文件__))
并仔细检查是否确实需要使用
exec
的情况。如果不能将脚本用作模块,则可能是设计出问题的迹象


请记住Python的Zen#8,如果您认为有一个很好的理由可以证明它必须适用于
exec
,那么请让我们了解更多有关问题背景的详细信息。

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

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类, 它支持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'
print '\t >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '\t << level 2'
print '\t\t >> level 3'
print '\t\t\t I can see the earths core.'
print '\t\t << level 3'
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
已加载(/Users/synthezerpatel/deep.py)
>>一级
已加载(/Users/synthezerpatel/deepher.py)
>>二级
已加载(/Users/synthezerpatel/)
已加载(/tmp/deep.py)
>>三级
我能看到地核。

这是一个局部解决方案,仍然比迄今为止所有已发表的方案都要好

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]
    不起作用,如果使用
    python-c“execfile('path-tester.py')”执行脚本,将返回
    -c
  • 我在上发布了一个完整的测试,欢迎您改进它

它在CPython、Jython、pypypy上工作。如果脚本是使用
execfile()
sys.argv[0]
\uuuu文件
执行的,那么它可以工作。如果脚本在内部,那么它可以工作。如果脚本是“导入的”(
PYTHONPATH=/path/to/library.zip python-mscript\u-to-run
)从zip文件;在本例中,它返回存档路径。如果脚本被编译成独立的可执行文件(
sys.freezed
),它就会工作。它适用于符号链接(
realpath
消除符号链接)。它在交互式解释器中工作;在这种情况下,它返回当前工作目录。

在大多数情况下,它应该工作:

import os,sys
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
希望这有助于: 如果您从任何地方运行脚本/模块,您都可以访问
\uuuu文件\uuuu
变量,该变量是表示脚本位置的模块变量

另一方面,如果您使用的是解释器,您没有访问该变量的权限,您将在其中获得一个名称
namererror
os.getcwd()
如果您从其他地方运行该文件,它将为您提供不正确的目录

在所有情况下,解决方案都应满足您的需求:

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

我还没有完全测试它,但它解决了我的问题。

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

您还可以使用
\uuuu文件\uuuu
来避免
检查
模块:

从pathlib导入路径
父项=路径(文件)
from inspect import getsourcefile
from os.path import abspath
abspath(getsourcefile(lambda:0))
from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent
from pathlib import Path
script_dir = Path(__file__).parent
$ pip install locate

$ python
>>> from locate import this_dir
>>> print(this_dir())
C:/Users/simon
from pathlib import Path
__dirpath__ = Path(globals().get("__file__", "./_")).absolute().parent
import os
__dirpath__ = os.path.dirname(os.path.abspath(globals().get("__file__", "./_")))
test_dir (in the home dir)
├── main.py
└── test_subdir
    ├── script1.py
    └── script2.py
~/test_dir/test_subdir
~/test_dir
print(__import__("pathlib").Path(__file__).parent)