如何检索模块的路径?

时间:2008-10-29 17:52:41

标签: python module inotify

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

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

20 个答案:

答案 0 :(得分:733)

import a_module
print(a_module.__file__)

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

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

您也可以尝试:

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

获取模块的目录。

答案 1 :(得分:221)

python中有inspect个模块。

Official documentation

  

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

示例:

>>> 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'

答案 2 :(得分:64)

正如其他答案所说,最好的方法是使用__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 

希望这会有所帮助。在测试所提出的其他解决方案时,这个警告花费了我很多时间和困惑。

答案 3 :(得分:34)

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

  1. 找到被调用脚本的路径
  2. 查找当前正在执行的脚本的路径
  3. 查找被调用脚本的目录
  4. (其中一些问题已在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放在目录栏中),然后调用

    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
    

    file_import_testing_link - &gt; file_import_testing.py

    使用检查

    @SummerBreeze使用inspect模块提及。

    对于导入的模块,这似乎运行良好,而且非常简洁:

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

    顺从地返回绝对路径。但是,为了找到当前正在执行的脚本的路径,我没有看到使用它的方法。

答案 4 :(得分:26)

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

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,然后在sys.meta_path中搜索合适的规范   给予发现者的“路径”的价值。如果没有规范可以返回无   被发现。

     

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

     

name和package参数与importlib.import_module()的作用相同。   换句话说,相对模块名称(带有前导点)可以工作。

答案 5 :(得分:18)

这是微不足道的。

每个模块都有一个__file__变量,显示了您现在所处位置的相对路径。

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

os.path.dirname(__file__)

答案 6 :(得分:17)

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

答案 7 :(得分:9)

命令行实用程序

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

python-which <package name>

enter image description here

创建/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

答案 8 :(得分:7)

所以我花了相当多的时间尝试使用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__))

答案 9 :(得分:7)

import module
print module.__path__
  

Packages支持另一个特殊属性__path__。这是   初始化为包含目录保存名称的列表   在执行该文件中的代码之前,程序包的__init__.py。   这个变量可以修改;这样做会影响未来的搜索   包中包含的模块和子包。

     

虽然通常不需要此功能,但可以使用它来扩展   在包中找到的一组模块。

Source

答案 10 :(得分:4)

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

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

答案 11 :(得分:3)

如果使用__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()。它将目录设置为.,这意味着当前目录,并且是任何与路径相关的函数的有效目录。

因此,并非真正需要使用abspath()。但是如果你仍然使用它,则不需要诀窍:abspath()接受空白路径并将其正确解释为当前目录。

答案 12 :(得分:3)

我想提供一个常见的场景(在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

答案 13 :(得分:1)

如果您希望在&#34;程序中动态执行此操作&#34;试试这段代码:
我的观点是,您可能不知道该模块的确切名称为&#34; hardcode&#34;它。 它可以从列表中选择,也可能当前没有运行以使用__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+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

我试图摆脱&#34;全球&#34;问题,但发现它不起作用的情况 我认为&#34; execfile()&#34;可以在Python 3中模拟 由于这是在程序中,因此可以很容易地将其放入方法或模块中以供重用。

答案 14 :(得分:1)

在python包的模块中,我必须引用与package位于同一目录中的文件。实施例

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 '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

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

答案 15 :(得分:1)

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

from pathlib import Path

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

cwd() method

  

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

resolve() method

  

使路径绝对,解决所有符号链接。返回一个新的路径对象:

答案 16 :(得分:1)

导入模块时,您可以访问大量信息。签出dir(a_module)。至于路径,有一个小问题: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'>

答案 17 :(得分:0)

如果您想从包的任何模块中检索包的根路径,则可以进行以下工作(在Python 3.6上进行了测试):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

__init__.py路径也可以通过使用__file__来引用。

希望这会有所帮助!

答案 18 :(得分:0)

如果您是使用pip安装的,则“ pip show”效果很好(“位置”)

$ pip show detectron2

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

答案 19 :(得分:0)

这是一个快速的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 ~]#