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

时间:2021-06-11 07:08:42

I would like to see what is best way to determine current script directory in python?

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

I discovered that two to the many ways of calling python code, it is hard to find a good solution.

我发现两种调用python代码的方式,很难找到一个好的解决方案。

Here are some problems:

这里有一些问题:

  • __file__ is not defined if the script is executed with exec, execfile
  • 如果脚本是用exec、execfile执行的,则不定义__file__
  • __module__ is defined only in modules
  • __module__仅在模块中定义

Use cases:

用例:

  • ./myfile.py
  • 。/ myfile.py
  • python myfile.py
  • python myfile.py
  • ./somedir/myfile.py
  • / somedir / myfile.py
  • python somedir/myfile.py
  • python somedir / myfile.py
  • execfile('myfile.py') (from another script, that can be located in another directory and that can have another current directory.
  • execfile('myfile.py')(来自另一个脚本,它可以位于另一个目录,并且可以有另一个当前目录。

I know that there is no perfect solution, because in some cases but I'm looking for the best approach that solved most of the cases.

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

The most used approach is os.path.dirname(os.path.abspath(__file__)) but this really doesn't work if you execute the script from another one with exec().

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

Warning

Any solution that uses current directory will fail, this can be different based on the way the script is called or it can be changed inside the running script.

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

12 个解决方案

#1


137  

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

is indeed the best you're going to get.

是你能得到的最好的。

It's unusual to be executing a script with exec/execfile; normally you should be using the module infrastructure to load scripts. If you must use these methods, I suggest setting __file__ in the globals you pass to the script so it can read that filename.

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

There's no other way to get the filename in execed code: as you note, the CWD may be in a completely different place.

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

#2


100  

If you really want to cover the case that a script is called via execfile(...), you can use the inspect module to deduce the filename (including the path). As far as I am aware, this will work for all cases you listed:

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

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

#3


36  

#!/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())

It works on CPython, Jython, Pypy. It works if the script is executed using execfile() (sys.argv[0] and __file__ -based solutions would fail here). It works if the script is inside an executable zip file (/an egg). It works if the script is "imported" (PYTHONPATH=/path/to/library.zip python -mscript_to_run) from a zip file; it returns the archive path in this case. It works if the script is compiled into a standalone executable (sys.frozen). It works for symlinks (realpath eliminates symbolic links). It works in an interactive interpreter; it returns the current working directory in this case.

它适用于CPython、Jython和Pypy。如果脚本是使用execfile() (sys)执行的,它就会工作。argv[0]和基于__file__的解决方案在这里将失败)。如果脚本在可执行的zip文件(/一个鸡蛋)中,它就可以工作。如果脚本是“导入的”(PYTHONPATH=/path/to/库),它就会起作用。从zip文件中压缩python -mscript_to_run;在本例中,它返回归档路径。如果脚本被编译成一个独立的可执行文件(system .frozen),那么它就可以工作。它适用于符号链接(realpath消除了符号链接)。它在交互式解释器中工作;在本例中,它返回当前工作目录。

#4


12  

In Python 3.4+ you can use the simpler pathlib module:

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

from inspect import currentframe, getframeinfo
from pathlib import Path

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

#5


5  

Just use os.path.dirname(os.path.abspath(__file__)) and examine very carefully whether there is a real need for the case where exec is used. It could be a sign of troubled design if you are not able to use your script as a module.

只需使用os.path.dirname(os.path.abspath(__file__))并仔细检查是否真正需要使用exec。如果不能将脚本作为模块使用,这可能是设计出现问题的征兆。

Keep in mind Zen of Python #8, and if you believe there is a good argument for a use-case where it must work for exec, then please let us know some more details about the background of the problem.

请记住Python #8的Zen,如果您认为一个用例必须适用于exec,那么请让我们了解更多关于问题背景的细节。

#6


3  

First.. a couple missing use-cases here if we're talking about ways to inject anonymous code..

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

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

But, the real question is, what is your goal - are you trying to enforce some sort of security? Or are you just interested in whats being loaded.

但是,真正的问题是,你的目标是什么——你是在试图加强某种安全性吗?或者你只是对装的东西感兴趣。

If you're interested in security, the filename that is being imported via exec/execfile is inconsequential - you should use rexec, which offers the following:

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

This module contains the RExec class, which supports r_eval(), r_execfile(), r_exec(), and r_import() methods, which are restricted versions of the standard Python functions eval(), execfile() and the exec and import statements. Code executed in this restricted environment will only have access to modules and functions that are deemed safe; you can subclass RExec add or remove capabilities as desired.

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

However, if this is more of an academic pursuit.. here are a couple goofy approaches that you might be able to dig a little deeper into..

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

Example scripts:

示例脚本:

./deep.py

。/ deep.py

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

./deeper.py

。/ deeper.py

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

/tmp/deepest.py

/ tmp / deepest.py

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

./codespy.py

。/ 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)

Output

输出

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

Of course, this is a resource-intensive way to do it, you'd be tracing all your code.. Not very efficient. But, I think it's a novel approach since it continues to work even as you get deeper into the nest. You can't override 'eval'. Although you can override execfile().

当然,这是一种资源密集型的方法,您需要跟踪所有的代码。不是很有效率。但是,我认为这是一种新颖的方法,因为即使在你深入到巢穴的时候,这种方法仍然有效。你不能覆盖的eval。尽管可以重写execfile()。

Note, this approach only coveres exec/execfile, not 'import'. For higher level 'module' load hooking you might be able to use use sys.path_hooks (Write-up courtesy of PyMOTW).

注意,这种方法只涉及exec/execfile,而不涉及“导入”。对于更高级别的“模块”加载连接,您可能可以使用sys。path_hooks (PyMOTW提供的注释)。

Thats all I have off the top of my head.

这就是我脑子里想的。

#7


2  

Here is a partial solution, still better than all published ones so far.

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

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__))

Now this works will all calls but if someone use chdir() to change the current directory, this will also fail.

现在,该操作将执行所有调用,但是如果有人使用chdir()更改当前目录,那么该操作也将失败。

Notes:

注:

  • sys.argv[0] is not going to work, will return -c if you execute the script with python -c "execfile('path-tester.py')"
  • sys。argv[0]不会工作,如果您使用python -c执行脚本,将返回-c“execfile('path-tester.py')”
  • I published a complete test at https://gist.github.com/1385555 and you are welcome to improve it.
  • 我在https://gist.github.com/1385555上发布了一个完整的测试,欢迎您对它进行改进。

#8


2  

This should work in most cases:

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

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

#9


1  

Hopefully this helps:- If you run a script/module from anywhere you'll be able to access the __file__ variable which is a module variable representing the location of the script.

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

On the other hand, if you're using the interpreter you don't have access to that variable, where you'll get a name NameError and os.getcwd() will give you the incorrect directory if you're running the file from somewhere else.

另一方面,如果您正在使用解释器,那么您将无法访问该变量,您将获得一个名称NameError,如果您正在从其他地方运行文件,那么os.getcwd()将给出错误的目录。

This solution should give you what you're looking for in all cases:

这个解决方案应该给你在所有情况下都要找的东西:

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

I haven't thoroughly tested it but it solved my problem.

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

#10


0  

Would

import os
cwd = os.getcwd()

do what you want? I'm not sure what exactly you mean by the "current script directory". What would the expected output be for the use cases you gave?

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

#11


0  

The os.path... approach was the 'done thing' in Python 2.

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

In Python 3, you can find directory of script as follows:

在Python 3中,脚本目录如下:

from pathlib import Path
cwd = Path(__file__).parents[0]

#12


0  

import os
import sys

def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))


my_script_dir = get_script_path()
print my_script_dir

This gives you the directory of the script at the top of the stack (i.e. the one being executed - not Python's, which is usually the first executed, returning C:/)

这将为您提供堆栈顶部的脚本目录(即正在执行的脚本——而不是Python的,后者通常是第一个执行的,返回C:/)

#1


137  

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

is indeed the best you're going to get.

是你能得到的最好的。

It's unusual to be executing a script with exec/execfile; normally you should be using the module infrastructure to load scripts. If you must use these methods, I suggest setting __file__ in the globals you pass to the script so it can read that filename.

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

There's no other way to get the filename in execed code: as you note, the CWD may be in a completely different place.

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

#2


100  

If you really want to cover the case that a script is called via execfile(...), you can use the inspect module to deduce the filename (including the path). As far as I am aware, this will work for all cases you listed:

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

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

#3


36  

#!/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())

It works on CPython, Jython, Pypy. It works if the script is executed using execfile() (sys.argv[0] and __file__ -based solutions would fail here). It works if the script is inside an executable zip file (/an egg). It works if the script is "imported" (PYTHONPATH=/path/to/library.zip python -mscript_to_run) from a zip file; it returns the archive path in this case. It works if the script is compiled into a standalone executable (sys.frozen). It works for symlinks (realpath eliminates symbolic links). It works in an interactive interpreter; it returns the current working directory in this case.

它适用于CPython、Jython和Pypy。如果脚本是使用execfile() (sys)执行的,它就会工作。argv[0]和基于__file__的解决方案在这里将失败)。如果脚本在可执行的zip文件(/一个鸡蛋)中,它就可以工作。如果脚本是“导入的”(PYTHONPATH=/path/to/库),它就会起作用。从zip文件中压缩python -mscript_to_run;在本例中,它返回归档路径。如果脚本被编译成一个独立的可执行文件(system .frozen),那么它就可以工作。它适用于符号链接(realpath消除了符号链接)。它在交互式解释器中工作;在本例中,它返回当前工作目录。

#4


12  

In Python 3.4+ you can use the simpler pathlib module:

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

from inspect import currentframe, getframeinfo
from pathlib import Path

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

#5


5  

Just use os.path.dirname(os.path.abspath(__file__)) and examine very carefully whether there is a real need for the case where exec is used. It could be a sign of troubled design if you are not able to use your script as a module.

只需使用os.path.dirname(os.path.abspath(__file__))并仔细检查是否真正需要使用exec。如果不能将脚本作为模块使用,这可能是设计出现问题的征兆。

Keep in mind Zen of Python #8, and if you believe there is a good argument for a use-case where it must work for exec, then please let us know some more details about the background of the problem.

请记住Python #8的Zen,如果您认为一个用例必须适用于exec,那么请让我们了解更多关于问题背景的细节。

#6


3  

First.. a couple missing use-cases here if we're talking about ways to inject anonymous code..

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

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

But, the real question is, what is your goal - are you trying to enforce some sort of security? Or are you just interested in whats being loaded.

但是,真正的问题是,你的目标是什么——你是在试图加强某种安全性吗?或者你只是对装的东西感兴趣。

If you're interested in security, the filename that is being imported via exec/execfile is inconsequential - you should use rexec, which offers the following:

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

This module contains the RExec class, which supports r_eval(), r_execfile(), r_exec(), and r_import() methods, which are restricted versions of the standard Python functions eval(), execfile() and the exec and import statements. Code executed in this restricted environment will only have access to modules and functions that are deemed safe; you can subclass RExec add or remove capabilities as desired.

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

However, if this is more of an academic pursuit.. here are a couple goofy approaches that you might be able to dig a little deeper into..

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

Example scripts:

示例脚本:

./deep.py

。/ deep.py

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

./deeper.py

。/ deeper.py

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

/tmp/deepest.py

/ tmp / deepest.py

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

./codespy.py

。/ 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)

Output

输出

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

Of course, this is a resource-intensive way to do it, you'd be tracing all your code.. Not very efficient. But, I think it's a novel approach since it continues to work even as you get deeper into the nest. You can't override 'eval'. Although you can override execfile().

当然,这是一种资源密集型的方法,您需要跟踪所有的代码。不是很有效率。但是,我认为这是一种新颖的方法,因为即使在你深入到巢穴的时候,这种方法仍然有效。你不能覆盖的eval。尽管可以重写execfile()。

Note, this approach only coveres exec/execfile, not 'import'. For higher level 'module' load hooking you might be able to use use sys.path_hooks (Write-up courtesy of PyMOTW).

注意,这种方法只涉及exec/execfile,而不涉及“导入”。对于更高级别的“模块”加载连接,您可能可以使用sys。path_hooks (PyMOTW提供的注释)。

Thats all I have off the top of my head.

这就是我脑子里想的。

#7


2  

Here is a partial solution, still better than all published ones so far.

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

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__))

Now this works will all calls but if someone use chdir() to change the current directory, this will also fail.

现在,该操作将执行所有调用,但是如果有人使用chdir()更改当前目录,那么该操作也将失败。

Notes:

注:

  • sys.argv[0] is not going to work, will return -c if you execute the script with python -c "execfile('path-tester.py')"
  • sys。argv[0]不会工作,如果您使用python -c执行脚本,将返回-c“execfile('path-tester.py')”
  • I published a complete test at https://gist.github.com/1385555 and you are welcome to improve it.
  • 我在https://gist.github.com/1385555上发布了一个完整的测试,欢迎您对它进行改进。

#8


2  

This should work in most cases:

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

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

#9


1  

Hopefully this helps:- If you run a script/module from anywhere you'll be able to access the __file__ variable which is a module variable representing the location of the script.

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

On the other hand, if you're using the interpreter you don't have access to that variable, where you'll get a name NameError and os.getcwd() will give you the incorrect directory if you're running the file from somewhere else.

另一方面,如果您正在使用解释器,那么您将无法访问该变量,您将获得一个名称NameError,如果您正在从其他地方运行文件,那么os.getcwd()将给出错误的目录。

This solution should give you what you're looking for in all cases:

这个解决方案应该给你在所有情况下都要找的东西:

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

I haven't thoroughly tested it but it solved my problem.

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

#10


0  

Would

import os
cwd = os.getcwd()

do what you want? I'm not sure what exactly you mean by the "current script directory". What would the expected output be for the use cases you gave?

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

#11


0  

The os.path... approach was the 'done thing' in Python 2.

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

In Python 3, you can find directory of script as follows:

在Python 3中,脚本目录如下:

from pathlib import Path
cwd = Path(__file__).parents[0]

#12


0  

import os
import sys

def get_script_path():
    return os.path.dirname(os.path.realpath(sys.argv[0]))


my_script_dir = get_script_path()
print my_script_dir

This gives you the directory of the script at the top of the stack (i.e. the one being executed - not Python's, which is usually the first executed, returning C:/)

这将为您提供堆栈顶部的脚本目录(即正在执行的脚本——而不是Python的,后者通常是第一个执行的,返回C:/)