__file__ 变量的含义/作用是什么?

发布于 2025-01-05 16:52:42 字数 295 浏览 0 评论 0 原文

import os

A = os.path.join(os.path.dirname(__file__), '..')

B = os.path.dirname(os.path.realpath(__file__))

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

我通常只是将它们与实际路径硬连线。但是这些在运行时确定路径的语句是有原因的,我真的很想了解 os.path 模块,以便我可以开始使用它。

import os

A = os.path.join(os.path.dirname(__file__), '..')

B = os.path.dirname(os.path.realpath(__file__))

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

I usually just hard-wire these with the actual path. But there is a reason for these statements that determine path at runtime, and I would really like to understand the os.path module so that I can start using it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

转身泪倾城 2025-01-12 16:52:42

当从 Python 中的文件加载模块时,__file__ 将设置为其 绝对路径。然后,您可以将其与其他函数一起使用来查找文件所在的目录。

一次一个示例:

A = os.path.join(os.path.dirname(__file__), '..')
# A is the parent directory of the directory where program resides.

B = os.path.dirname(os.path.realpath(__file__))
# B is the canonicalised (?) directory where the program resides.

C = os.path.abspath(os.path.dirname(__file__))
# C is the absolute path of the directory where the program resides.

您可以在此处看到从这些函数返回的各种值:

import os
print(__file__)
print(os.path.join(os.path.dirname(__file__), '..'))
print(os.path.dirname(os.path.realpath(__file__)))
print(os.path.abspath(os.path.dirname(__file__)))

并确保从不同位置运行它(例如./text.py~/python/text.py 等等)看看有什么区别。

When a module is loaded from a file in Python, __file__ is set to its absolute path. You can then use that with other functions to find the directory that the file is located in.

Taking your examples one at a time:

A = os.path.join(os.path.dirname(__file__), '..')
# A is the parent directory of the directory where program resides.

B = os.path.dirname(os.path.realpath(__file__))
# B is the canonicalised (?) directory where the program resides.

C = os.path.abspath(os.path.dirname(__file__))
# C is the absolute path of the directory where the program resides.

You can see the various values returned from these here:

import os
print(__file__)
print(os.path.join(os.path.dirname(__file__), '..'))
print(os.path.dirname(os.path.realpath(__file__)))
print(os.path.abspath(os.path.dirname(__file__)))

and make sure you run it from different locations (such as ./text.py, ~/python/text.py and so forth) to see what difference that makes.

深居我梦 2025-01-12 16:52:42

我只想先解决一些困惑。 __file__ 不是通配符,它​​是一个属性。按照惯例,双下划线属性和方法被认为是“特殊”的,并且有特殊的用途。

http://docs.python.org/reference/datamodel.html 显示了许多特殊方法和属性,如果不是全部的话。

在本例中,__file__ 是模块(模块对象)的属性。在 Python 中,.py 文件是一个模块。所以import amodule将会有一个__file__属性,在不同的情况下意味着不同的东西。

摘自文档:

__file__ 是加载模块的文件的路径名(如果是从文件加载的话)。 __file__ 属性不存在
对于静态链接到解释器的 C 模块;为了
从共享库动态加载的扩展模块,它是
共享库文件的路径名。

在您的情况下,模块正在全局命名空间中访问它自己的 __file__ 属性。

要查看实际效果,请尝试:

# file: test.py

print globals()
print __file__

并运行:

python test.py

{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__':
 'test_print__file__.py', '__doc__': None, '__package__': None}
test_print__file__.py

I just want to address some confusion first. __file__ is not a wildcard it is an attribute. Double underscore attributes and methods are considered to be "special" by convention and serve a special purpose.

http://docs.python.org/reference/datamodel.html shows many of the special methods and attributes, if not all of them.

In this case __file__ is an attribute of a module (a module object). In Python a .py file is a module. So import amodule will have an attribute of __file__ which means different things under difference circumstances.

Taken from the docs:

__file__ is the pathname of the file from which the module was loaded, if it was loaded from a file. The __file__ attribute is not present
for C modules that are statically linked into the interpreter; for
extension modules loaded dynamically from a shared library, it is the
pathname of the shared library file.

In your case the module is accessing it's own __file__ attribute in the global namespace.

To see this in action try:

# file: test.py

print globals()
print __file__

And run:

python test.py

{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__file__':
 'test_print__file__.py', '__doc__': None, '__package__': None}
test_print__file__.py
人间不值得 2025-01-12 16:52:42

根据文档

__file__ 是模块所在文件的路径名
已加载(如果它是从文件加载的)。 __file__ 属性不是
存在于静态链接到解释器中的 C 模块;
对于从共享库动态加载的扩展模块,它是
共享库文件的路径名。

以及还有

__file__ 是文件的“路径”,除非模块是内置的(因此在 sys.builtin_module_names 中列出),在这种情况下,属性为未设置。

Per the documentation:

__file__ is the pathname of the file from which the module was
loaded, if it was loaded from a file. The __file__ attribute is not
present for C modules that are statically linked into the interpreter;
for extension modules loaded dynamically from a shared library, it is
the pathname of the shared library file.

and also:

__file__ is to be the “path” to the file unless the module is built-in (and thus listed in sys.builtin_module_names) in which case the attribute is not set.

乱世争霸 2025-01-12 16:52:42

只是在这里添加一个关于可能使某些人感到困惑的更改的快速注释(主要是回答问题的标题而不是其描述)。从 Python 3.4 开始,__file__ 的行为方式发生了细微变化:

  • 如果直接执行该模块,则将其设置为使用它的模块的相对路径。
  • 否则它被设置为文件的绝对路径。

模块 __file__ 属性(和相关值)现在默认应始终包含绝对路径,唯一的例外是当直接使用脚本执行时 __main__.__file__相对路径。 (由 Brett Cannon 在问题 18416 中贡献。)

示例

直接调用模块 x和模块 y 间接:

# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())

# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))

运行 python3 x.py 将输出:

/home/aderchox/mytest/y.py                                                                                                                       
/home/aderchox/mytest/y.py                                                                                                                       
x.py                                                                                                                                             
x.py                                                                                                                                             
/home/aderchox/mytest/x.py

Just going to add a quick note here (mostly answering the question's title rather than its description) about a change which can confuse some people. As of Python 3.4 there has been a slight change in how the __file__ behaves:

  • It's set to the relative path of the module in which it's used, if that module is executed directly.
  • It's set to the absolute path of the file otherwise.

Module __file__ attributes (and related values) should now always contain absolute paths by default, with the sole exception of __main__.__file__ when a script has been executed directly using a relative path. (Contributed by Brett Cannon in issue 18416.)

Example:

Calling module x directly and module y indirectly:

# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())

# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))

Running python3 x.py will output:

/home/aderchox/mytest/y.py                                                                                                                       
/home/aderchox/mytest/y.py                                                                                                                       
x.py                                                                                                                                             
x.py                                                                                                                                             
/home/aderchox/mytest/x.py
扎心 2025-01-12 16:52:42

将 __file__ 与各种 os.path 模块结合使用可以让所有路径相对于当前模块的目录位置。这允许您的模块/项目可以移植到其他机器。

在您的项目中,您执行以下操作:

A = '/Users/myname/Projects/mydevproject/somefile.txt'

然后尝试使用 /home/web/mydevproject/ 之类的部署目录将其部署到服务器,然后您的代码将无法正确找到路径。

Using __file__ combined with various os.path modules lets all paths be relative the current module's directory location. This allows your modules/projects to be portable to other machines.

In your project you do:

A = '/Users/myname/Projects/mydevproject/somefile.txt'

and then try to deploy it to your server with a deployments directory like /home/web/mydevproject/ then your code won't be able to find the paths correctly.

娜些时光,永不杰束 2025-01-12 16:52:42

要添加到 aderchox 的答案中,__file__ 变量的行为在 Python 3.9 中再次更改,现在在所有情况下它都是绝对路径

运行相同的示例(但将其复制到此处以实现自我一致性)

# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())

# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))

现在运行x.py 具有两个不同版本的解释器

$ python3.8 x.py
/private/tmp/y.py
/private/tmp/y.py
x.py
x.py
/private/tmp/x.py

$ python3.9 x.py
/private/tmp/y.py
/private/tmp/y.py
/private/tmp/x.py
/private/tmp/x.py
/private/tmp/x.py

源:
https://docs.python.org/3/whatsnew/3.9 .html#其他语言更改

To add to aderchox's answer, the behaviour of the __file__ variable was again changed in Python 3.9, and now it's an absolute Path in all cases

Running the same example (but copying it here for self consistency)

# x.py:
from pathlib import Path
import y
print(__file__)
print(Path(__file__))
print(Path(__file__).resolve())

# y.py:
from pathlib import Path
print(__file__)
print(Path(__file__))

Now running x.py with two different versions of the interpreter

$ python3.8 x.py
/private/tmp/y.py
/private/tmp/y.py
x.py
x.py
/private/tmp/x.py

$ python3.9 x.py
/private/tmp/y.py
/private/tmp/y.py
/private/tmp/x.py
/private/tmp/x.py
/private/tmp/x.py

source:
https://docs.python.org/3/whatsnew/3.9.html#other-language-changes

最终幸福 2025-01-12 16:52:42

使用死灵术

[仅在 PYTHON 3.7 中测试]

我使用:

os.sep.join(__file__.split(os.sep)[:-1])

与我见过的其他解决方案相比,我更喜欢它。我编写的一些测试代码:

from timeit import Timer
from typing import List, Tuple

N = 100000
TIMEITOUT = [None]


def _p_timeit(stmt: str, setup: str = ""):
    tte = Timer(f"TIMEITOUT[0]={stmt}", setup=f"{setup};from __main__ import TIMEITOUT").timeit(N)
    print(f"{stmt:<54}|{tte:>17.10f}    [output]: \"{TIMEITOUT[0]}\"")
    return stmt, tte


def _p_header():
    print(f"Testing w/ number={N} iterations\n{'=' * 72}")
    print(f"{'Statement':<54}|{'Time':^17}\n{'-' * 72}")


def _p_compare(a: Tuple[str, float], b_l: List[Tuple[str, float]]):
    print(f"\n{'=' * 72}\nComparing {a[0]} to all other statements:\n{'-' * 72}")
    for b in b_l:
        d = (b[1]-a[1])/a[1]
        cmp = f"faster than" if d > 0 else f"slower than" if d < 0 else f"equally (t={a[1]}) as fast as"
        print(f"{a[0]} was {(abs(d)*100):.2f}% {cmp} {b[0]}")


_p_header()

my_suggestion = _p_timeit("os.sep.join(__file__.split(os.sep)[:-1])", setup="import os")
others = [_p_timeit("os.path.abspath(os.path.dirname(__file__))", setup="import os"),
          _p_timeit("Path(__file__).parent", setup="from pathlib import Path"),
          _p_timeit("Path(__file__).resolve().parent", setup="from pathlib import Path")]
_p_compare(my_suggestion, others)

输出:

Testing w/ number=100000 iterations
========================================================================
Statement                                             |      Time       
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1])              |     0.0640765000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
os.path.abspath(os.path.dirname(__file__))            |     0.6156060000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).parent                                 |     0.7117664000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).resolve().parent                       |     9.3563913000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\Lib"

========================================================================
Comparing os.sep.join(__file__.split(os.sep)[:-1]) to all other statements:
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1]) was 860.74% faster than os.path.abspath(os.path.dirname(__file__))
os.sep.join(__file__.split(os.sep)[:-1]) was 1010.81% faster than Path(__file__).parent
os.sep.join(__file__.split(os.sep)[:-1]) was 14501.91% faster than Path(__file__).resolve().parent

请记住,如果 __file__ 使用除 os.sep 之外的任何分隔符(例如:os.altsep)返回字符串,则程序将失败。我没有受到这种影响,但谁知道这些天...

如果需要的话,您总是可以先在字符串中找到分隔符,然后使用它而不是 os.sep。根据时间复杂度标准(找到分离器的时间基本上是恒定的),速度的改进将保持不变。

Necromancy engaged

[ONLY TESTED IN PYTHON 3.7]

I use:

os.sep.join(__file__.split(os.sep)[:-1])

And I prefer it over the other solutions I've seen provided. Some test code I wrote:

from timeit import Timer
from typing import List, Tuple

N = 100000
TIMEITOUT = [None]


def _p_timeit(stmt: str, setup: str = ""):
    tte = Timer(f"TIMEITOUT[0]={stmt}", setup=f"{setup};from __main__ import TIMEITOUT").timeit(N)
    print(f"{stmt:<54}|{tte:>17.10f}    [output]: \"{TIMEITOUT[0]}\"")
    return stmt, tte


def _p_header():
    print(f"Testing w/ number={N} iterations\n{'=' * 72}")
    print(f"{'Statement':<54}|{'Time':^17}\n{'-' * 72}")


def _p_compare(a: Tuple[str, float], b_l: List[Tuple[str, float]]):
    print(f"\n{'=' * 72}\nComparing {a[0]} to all other statements:\n{'-' * 72}")
    for b in b_l:
        d = (b[1]-a[1])/a[1]
        cmp = f"faster than" if d > 0 else f"slower than" if d < 0 else f"equally (t={a[1]}) as fast as"
        print(f"{a[0]} was {(abs(d)*100):.2f}% {cmp} {b[0]}")


_p_header()

my_suggestion = _p_timeit("os.sep.join(__file__.split(os.sep)[:-1])", setup="import os")
others = [_p_timeit("os.path.abspath(os.path.dirname(__file__))", setup="import os"),
          _p_timeit("Path(__file__).parent", setup="from pathlib import Path"),
          _p_timeit("Path(__file__).resolve().parent", setup="from pathlib import Path")]
_p_compare(my_suggestion, others)

Output:

Testing w/ number=100000 iterations
========================================================================
Statement                                             |      Time       
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1])              |     0.0640765000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
os.path.abspath(os.path.dirname(__file__))            |     0.6156060000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).parent                                 |     0.7117664000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\lib"
Path(__file__).resolve().parent                       |     9.3563913000    [output]: "C:\Users\abrewer\AppData\Local\Programs\Python\Python37\Lib"

========================================================================
Comparing os.sep.join(__file__.split(os.sep)[:-1]) to all other statements:
------------------------------------------------------------------------
os.sep.join(__file__.split(os.sep)[:-1]) was 860.74% faster than os.path.abspath(os.path.dirname(__file__))
os.sep.join(__file__.split(os.sep)[:-1]) was 1010.81% faster than Path(__file__).parent
os.sep.join(__file__.split(os.sep)[:-1]) was 14501.91% faster than Path(__file__).resolve().parent

Keep in mind that if __file__ returns a string using any separator (ex: os.altsep) other than os.sep, the program will fail. I haven't had this affect me, but who knows these days...

You could always find the separator in the string first if need be, then use that instead of os.sep. The speed improvements would, as per time complexity standards (time to find the separator is essentially constant), remain.

℉絮湮 2025-01-12 16:52:42

使用 pathlib.Path 处理此问题的最简单的“pythonic”方法是将其用作:

ex1 = Path(__file__).parent/"myfilename.xyz"



ex2 = Path(__file__).parent/"whatever_folder/myfilename.xyz"


ex3 = Path(__file__).parent/"../whatever_folder/myfilename.xyz"

因为您可以直接使用“/”。

The most simple, "pythonic" way of handling this with pathlib.Path would be to use it as:

ex1 = Path(__file__).parent/"myfilename.xyz"



ex2 = Path(__file__).parent/"whatever_folder/myfilename.xyz"


ex3 = Path(__file__).parent/"../whatever_folder/myfilename.xyz"

because you can use "/" directly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文