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

2024-12-17 08:30:00
admin
原创
140
摘要:问题描述: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(__f...

问题描述:

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模块,以便我可以开始使用它。


解决方案 1:

当从 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等等)运行它,以查看会产生什么差异。

解决方案 2:

我只是想先解决一些困惑。 __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

解决方案 3:

根据文件:

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

还有:​

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

解决方案 4:

这里只想简单说明一下(主要是回答问题的标题而不是描述),关于一个可能会让一些人感到困惑的变化。从 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

解决方案 5:

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

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

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

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

解决方案 6:

为了补充 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#other-language-changes

解决方案 7:

亡灵法术

[仅在 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
{'=' * 72}")
    print(f"{'Statement':<54}|{'Time':^17}
{'-' * 72}")


def _p_compare(a: Tuple[str, float], b_l: List[Tuple[str, float]]):
    print(f"
{'=' * 72}
Comparing {a[0]} to all other statements:
{'-' * 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:UsersabrewerAppDataLocalProgramsPythonPython37lib"
os.path.abspath(os.path.dirname(__file__))            |     0.6156060000    [output]: "C:UsersabrewerAppDataLocalProgramsPythonPython37lib"
Path(__file__).parent                                 |     0.7117664000    [output]: "C:UsersabrewerAppDataLocalProgramsPythonPython37lib"
Path(__file__).resolve().parent                       |     9.3563913000    [output]: "C:UsersabrewerAppDataLocalProgramsPythonPython37Lib"

========================================================================
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。根据时间复杂度标准(查找分隔符的时间基本不变),速度改进将保持不变。

解决方案 8:

使用 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"

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

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2560  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1552  
  IPD(Integrated Product Development)流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。其中,技术评审与决策评审是IPD流程中至关重要的环节,它们既有明显的区别,又存在紧密的协同关系。深入理解这两者的区别与协同,对于企业有效实施IPD流程,提升产品开发效率与质量具有重要意义...
IPD管理流程   1  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、ClickUp、Freshdesk、GanttPRO、Planview、Smartsheet、Asana、Nifty、HubPlanner、Teamwork。在当今快速变化的商业环境中,项目管理软件已成为企业提升效率、优化资源分配和确保项目按时交付的关键工具。然而...
项目管理系统   2  
  建设工程项目质量关乎社会公众的生命财产安全,也影响着企业的声誉和可持续发展。高质量的建设工程不仅能为使用者提供舒适、安全的环境,还能提升城市形象,推动经济的健康发展。在实际的项目操作中,诸多因素会对工程质量产生影响,从规划设计到施工建设,再到后期的验收维护,每一个环节都至关重要。因此,探寻并运用有效的方法来提升建设工程...
工程项目管理制度   3  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用