如何检索模块的路径?

2024-12-11 08:47:00
admin
原创
144
摘要:问题描述:我想检测模块是否已更改。现在,使用 inotify 很简单,您只需要知道要从哪个目录获取通知。如何在 python 中检索模块的路径?解决方案 1:import a_module print(a_module.__file__) 实际上会给你加载的.pyc 文件的路径,至少在 Mac OS X 上是...

问题描述:

我想检测模块是否已更改。现在,使用 inotify 很简单,您只需要知道要从哪个目录获取通知。

如何在 python 中检索模块的路径?


解决方案 1:

import a_module
print(a_module.__file__)

实际上会给你加载的.pyc 文件的路径,至少在 Mac OS X 上是这样。所以我想你可以这样做:

import os
path = os.path.abspath(a_module.__file__)

您还可以尝试:

path = os.path.dirname(a_module.__file__)

获取模块的目录。

解决方案 2:

inspectpython里有模块。

官方文档

inspect 模块提供了几个有用的函数来帮助获取有关活动对象(如模块、类、方法、函数、回溯、框架对象和代码对象)的信息。例如,它可以帮助您检查类的内容、检索方法的源代码、提取和格式化函数的参数列表,或者获取显示详细回溯所需的所有信息。

例子:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'

解决方案 3:

正如其他答案所说,最好的方法是使用__file__(下面再次演示)。但是,有一个重要的警告,即__file__如果您单独运行模块 (即作为__main__),则不存在。

例如,假设您有两个文件(它们都在您的 PYTHONPATH 上):

#/path1/foo.py
import bar
print(bar.__file__)

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

运行 foo.py 将给出输出:

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

但是如果你尝试单独运行 bar.py,你将得到:

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

希望这能有所帮助。在测试其他解决方案时,这个警告花费了我很多时间,也让我感到困惑。

解决方案 4:

我也会尝试解决这个问题的一些变体:

  1. 找到被调用脚本的路径

  2. 查找当前执行脚本的路径

  3. 找到被调用脚本的目录

(其中一些问题已在 SO 上提出,但已被关闭为重复问题并重定向到这里。)

使用注意事项__file__

对于您已导入的模块:

import something
something.__file__ 

将返回模块的绝对路径。但是,给定以下脚本 foo.py:

#foo.py
print '__file__', __file__

使用 'python foo.py' 调用它将仅返回 'foo.py'。如果你添加一个 shebang:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

并使用 ./foo.py 调用它,它将返回 './foo.py'。从不同的目录调用它(例如将 foo.py 放在目录 bar 中),然后调用

python bar/foo.py

或者添加 shebang 并直接执行文件:

bar/foo.py

将返回“bar/foo.py”(相对路径)。

查找目录

现在从那里获取目录os.path.dirname(__file__)也可能会比较棘手。至少在我的系统上,如果您从与文件相同的目录中调用它,它会返回一个空字符串。例如。

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

将输出:

__file__ is: foo.py
os.path.dirname(__file__) is: 

换句话说,它返回一个空字符串,因此如果您想将它用于当前文件(而不是导入模块的文件),这似乎并不可靠。为了解决这个问题,您可以将其包装在对 abspath 的调用中:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

输出类似以下内容:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

请注意,abspath() 不会解析符号链接。如果您想这样做,请改用 realpath()。例如,创建一个指向 file_import_testing.py 的符号链接 file_import_testing_link,内容如下:

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

执行将打印绝对路径,例如:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

文件导入测试链接-> 文件导入测试.py

使用检查

@SummerBreeze 提到使用检查模块。

对于导入的模块来说,这似乎效果很好,而且相当简洁:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

乖乖返回绝对路径。查找当前执行脚本的路径:

inspect.getfile(inspect.currentframe())

(感谢@jbochi)

inspect.getabsfile(inspect.currentframe()) 

给出当前正在执行的脚本的绝对路径(感谢@Sadman_Sakib)。

解决方案 5:

我不明白为什么没有人谈论这个问题,但对我来说,最简单的解决方案是使用imp.find_module("modulename")(文档在此处):

import imp
imp.find_module("os")

它给出一个第二位置上带有路径的元组:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

与“检查”方法相比,此方法的优势在于您无需导入模块即可使其工作,并且您可以在输入中使用字符串。例如,在检查另一个脚本中调用的模块时很有用。

编辑

在python3中,importlib模块应该这样做:

文档importlib.util.find_spec

返回指定模块的规范。

首先,检查 sys.modules 以查看模块是否已导入。如果已导入,则返回 sys.modules[name]. spec。如果恰好将其设置为 None,则引发 ValueError。如果模块不在 sys.modules 中,则使用提供给查找器的 'path' 值搜索 sys.meta_path 以查找合适的规范。如果找不到规范,则返回 None。

如果名称是子模块(包含点),则会自动导入父模块。

名称和包参数的作用与 importlib.import_module() 相同。换句话说,相对模块名称(以点开头)有效。

解决方案 6:

这本来就是小事一桩。

每个模块都有一个__file__变量,显示其相对于您当前所在位置的相对路径。

因此,获取模块通知它的目录很简单:

os.path.dirname(__file__)

解决方案 7:

import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

解决方案 8:

如果您想要检索模块路径而不加载它:

import importlib.util

print(importlib.util.find_spec("requests").origin)

示例输出:

/usr/lib64/python3.9/site-packages/requests/__init__.py

解决方案 9:

import module
print module.__path__

软件包还支持一个特殊属性,__path__。在执行该文件中的代码之前,它被初始化为包含软件包所在目录名称的列表__init__.py。此变量可以修改;修改后会影响将来对软件包中包含的模块和子软件包的搜索。

虽然此功能并不经常需要,但它可用于扩展包中的模块集。

来源

解决方案 10:

命令行实用程序

您可以将其调整为命令行实用程序,

python-which <package name>

在此处输入图片描述


创造/usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

使其可执行

sudo chmod +x /usr/local/bin/python-which

解决方案 11:

您只需导入模块,然后点击其名称,即可获得其完整路径

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

解决方案 12:

导入模块时,您可以访问大量信息。请查看dir(a_module)。至于路径,有一个 dunder:。a_module.__path__您也可以只打印模块本身。

>>> import a_module
>>> print(dir(a_module))
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> print(a_module.__path__)
['/.../.../a_module']
>>> print(a_module)
<module 'a_module' from '/.../.../a_module/__init__.py'>

解决方案 13:

呃……

>>> import logging
>>> print(logging)
<module 'logging' from 'C:\\Users\\Mike\\AppData\\Local\\Programs\\Python\\Python39\\lib\\logging\\__init__.py'>

解决方案 14:

所以我花了相当多的时间尝试使用 py2exe 来做到这一点,问题是获取脚本的基本文件夹,无论它是作为 python 脚本运行还是作为 py2exe 可执行文件运行。此外,无论是从当前文件夹、另一个文件夹还是(这是最难的)从系统路径运行,它都能正常工作。

最终我采用了这种方法,使用 sys.frozen 作为在 py2exe 中运行的指标:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))

解决方案 15:

如果您想从包的任何模块中检索包的根路径,则可以使用以下方法(在 Python 3.6 上测试):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

__init__.py也可以使用来引用主路径__file__

希望这有帮助!

解决方案 16:

如果您使用 pip 安装它,“pip show”效果很好('位置')

$ pip 显示 detector2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

更新:

$ python -m pip 显示我的模块

(作者:wisbucky)

解决方案 17:

如果您想知道脚本的绝对路径,可以使用Path对象:

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

cwd() 方法

返回一个代表当前目录的新路径对象(由 os.getcwd() 返回)

resolve() 方法

使路径绝对化,解析任何符号链接。返回一个新的路径对象:

解决方案 18:

如果使用时唯一的警告__file__是当前相对目录为空(即,当从脚本所在的同一目录运行时),那么一个简单的解决方案是:

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

结果如下:

$ python teste.py 
teste.py . /home/user/work/teste

诀窍在于调用or '.'之后dirname()。它将 dir 设置为.,这意味着当前目录,并且是任何与路径相关的函数的有效目录。

因此,使用abspath()并不是真正需要的。但是如果你还是使用它,就不需要这个技巧了:abspath()接受空白路径并正确地将其解释为当前目录。

解决方案 19:

我想贡献一个常见的场景(在 Python 3 中)并探索一些方法。

内置函数open()接受相对路径或绝对路径作为其第一个参数。相对路径被视为相对于当前工作目录,因此建议将绝对路径传递给文件。

简单地说,如果你使用以下代码运行脚本文件,则不能保证example.txt文件将在脚本文件所在的同一目录中创建:

with open('example.txt', 'w'):
    pass

要修复此代码,我们需要获取脚本的路径并使其绝对化。要确保路径绝对化,我们只需使用os.path.realpath()函数。要获取脚本的路径,有几个常用函数可返回各种路径结果:

  • os.getcwd()

  • os.path.realpath('example.txt')

  • sys.argv[0]

  • __file__

os.getcwd()和os.path.realpath()函数均基于当前工作目录返回路径结果。通常这不是我们想要的。sys.argv列表的第一个元素是根脚本(您运行的脚本)的路径,无论您是在根脚本本身中还是在其任何模块中调用该列表。在某些情况下,它可能派上用场。__file__变量包含调用它的模块的路径。


以下代码正确地example.txt在脚本所在的同一目录中创建一个文件:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

解决方案 20:

针对此问题的一个现代解决方案(Python >= 3.7)是importlib.resources.files()

from importlib import resources
resources.files(package_name)
# => WindowsPath("C:Path    oyourpackage\")

解决方案 21:

我必须从 Python 包的模块中引用与包位于同一目录中的文件。例如

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

因此,在上面我必须从 my_lib_a.py 模块调用 maincli.py,因为我知道 top_package 和 maincli.py 位于同一目录中。下面是我获取 maincli.py 路径的方法:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\n        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

根据 PlasmaBinturong 的帖子,我修改了代码。

解决方案 22:

如果您希望在“程序”中动态执行此操作,请尝试以下代码:

我的意思是,您可能不知道模块的确切名称,无法对其进行“硬编码”。它可能是从列表中选择的,也可能当前未运行以使用 __file__。

(我知道它在 Python 3 中不起作用)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"
")
f.write("modpath = "+modname+"
")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:Python27libos.pyc'>

我试图摆脱“全局”问题,但发现它不起作用的情况我认为“execfile()”可以在 Python 3 中模拟因为它在一个程序中,所以可以轻松地将其放入方法或模块中以供重用。

解决方案 23:

这是一个快速的 bash 脚本,希望对任何人都有用。我只想设置一个环境变量,这样我就可以pushd编写代码了。

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

Shell 示例:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#

解决方案 24:

如果您使用了pip,那么您可以调用pip show,但您必须使用您正在使用的特定版本来调用它python。例如,这些都可能产生不同的结果:

$ python -m pip show numpy
$ python2.7 -m pip show numpy
$ python3 -m pip show numpy

Location: /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python

不要简单地运行$ pip show numpy,因为无法保证pip不同python版本调用的结果是相同的。

解决方案 25:

如果你的导入是一个站点包(例如pandas),我建议这样做来获取它的目录(如果导入是一个模块,则不起作用,例如pathlib):

from importlib import resources  # part of core Python
import pandas as pd

package_dir = resources.path(package=pd, resource="").__enter__()

一般来说,当任务是访问站点包的路径/资源时,可以考虑importlib.resources 。

解决方案 26:

这里我打印cProfile包路径:-

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

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用