首页 文章

检索python模块路径

提问于
浏览
558

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

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

16 回答

  • 2

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

    • 找到被调用脚本的路径

    • 查找当前正在执行的脚本的路径

    • 查找被调用脚本的目录

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

    使用__file__的注意事项

    对于已导入的模块:

    import something
    something.__file__
    

    将返回模块的 absolute 路径 . 但是,给定下面的脚本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'( relative 路径) .

    查找目录

    现在从那里去获取目录, 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:
    

    换句话说,它返回一个空字符串,所以如果你想将它用于当前的 file (而不是导入模块的 file ),这似乎不可靠 . 要解决这个问题,你可以将它包装在对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 - > file_import_testing.py

    使用检查

    @SummerBreeze提到使用inspect模块 .

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

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

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

  • 19
    import module
    print module.__path__
    

    Packages支持另一个特殊属性__path__ . 这被初始化为一个列表,其中包含在执行该文件中的代码之前保存包的__init__.py的目录的名称 . 这个变量可以修改;这样做会影响将来对包中包含的模块和子包的搜索 . 虽然通常不需要此功能,但它可用于扩展程序包中的模块集 .

    Source

  • 2

    如果使用 __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
    

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

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

  • 7

    python中有 inspect 模块 .

    官方文件

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

    命令行实用程序

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

    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
    
  • 650

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

    from pathlib import Path
    
    print(Path().absolute())
    print(Path().resolve('.'))
    print(Path().cwd())
    

    cwd() method

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

    resolve() method

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

  • 1

    你可以导入你的模块,然后点击它的名字,你就会得到它的完整路径

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

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

    例如,假设您有两个文件(两个文件都在您的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
    

    希望这可以帮助 . 在测试其他解决方案时,这个警告花费了我很多时间和困惑呈现 .

  • 1
    import a_module
    print a_module.__file__
    

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

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

    你也可以试试

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

    获取目录以查找更改 .

  • 7

    我想贡献一个常见的场景(在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
    
  • 59

    这是微不足道的 .

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

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

    os.path.dirname(__file__)
    
  • 1

    所以我花了相当多的时间尝试用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__))
    
  • 32
    import os
    path = os.path.abspath(__file__)
    dir_path = os.path.dirname(path)
    
  • 23

    从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的发布,我修改了代码 .

  • 3

    如果您希望在"program"中动态执行此操作,请尝试以下代码:
    我的观点是,你可能不知道模块的确切名称"hardcode"它 . 它可以从列表中选择,也可能当前没有运行以使用__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'>
    

    我试图摆脱“全局”问题,但发现它不起作用的情况我认为“execfile()”可以在Python 3中模拟因为这是在一个程序中,它可以很容易地放在方法或模块中重用 .

  • 202

    我不明白为什么没有人在谈论这个,但对我来说最简单的解决方案是使用 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))
    

    这种方法优于“检查”方法的优点是您不需要导入模块使其工作,您可以在输入中使用字符串 . 例如,检查在另一个脚本中调用的模块时很有用 .

    EDIT

    在python3中, importlib 模块应该:

    importlib.util.find_spec 的文件:

    返回指定模块的规格 . 首先,检查sys.modules以查看模块是否已导入 . 如果是,则返回sys.modules [name] .spec . 如果恰好将其设置为None,则会引发ValueError . 如果模块不在sys.modules中,则会在sys.meta_path中搜索合适的规范,并为查找程序提供值“path” . 如果找不到规范,则返回None . 如果名称用于子模块(包含点),则会自动导入父模块 . name和package参数与importlib.import_module()的作用相同 . 换句话说,相对模块名称(带有前导点)起作用 .

相关问题