【问题标题】:Path issues with pkgutil.iter_modules() on WindowsWindows 上 pkgutil.iter_modules() 的路径问题
【发布时间】:2016-02-14 23:38:41
【问题描述】:

我正在尝试在运行时动态导入与模式匹配的 Python 模块。这些模块位于 Python 包中。

我用来查找模块的函数是:

def load_modules_from_dir(dirname, pattern=""):
    modules = []
    for importer, package_name, _ in pkgutil.iter_modules([dirname]):
        if re.search(pattern, package_name):
            full_package_name = '%s.%s' % (dirname, package_name)
            if full_package_name not in sys.modules:
                module = importer.find_module(package_name).load_module(full_package_name)
                modules.append(module)
    return modules

我这样称呼它:

module_dir = os.path.join(os.path.dirname(__file__))
modules = utils.load_modules_from_dir(module_dir, "jscal$")

在 Linux 上它会找到所有模块,但在 Windows 上它根本找不到任何模块。如果我在函数load_modules_from_dir 中打印dirname,我得到:H:\temp\linx\dist\calibrate\dcljscal

我已经在 Windows 上的 Python shell 中复制了它,并将其固定在路径分隔符上。以下内容一无所获:

>>> for x in pkgutil.iter_modules(['H:\temp\linx\dist\calibrate\dcljscal']):print x
...
>>> 

如果我用 Linux 替换 Windows 路径分隔符,它可以工作:

>>> for x in pkgutil.iter_modules(['H:/temp/linx/dist/calibrate/dcljscal']):print x
...
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'demojscal', True)
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'dx2cremjscal', True)
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'linxjscal', True)
>>>

如果我用\\ 替换\ 也可以,基本上是转义Windows 路径分隔符:

>>> for x in pkgutil.iter_modules(['H:\\temp\\linx\\dist\\calibrate\\dcljscal']):print x
...
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'demojscal', True)
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'dx2cremjscal', True)
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'linxjscal', True)
>>>

看来os.path.join(os.path.dirname(__file__))生成的路径是不可移植的。
我希望os.path.join() 会给我一条正确的路径,我可以在pkgutil.iter_modules() 中原封不动地使用它。我在这里做错了什么?

我在 Windows XP 上使用 Python 2.7.11。

【问题讨论】:

  • 盯着'\t' 不会给你任何警报?
  • @eryksun 是的,你是对的。如果我用\\t 替换\t,它也适用于Python shell。但你让我思考。 os.path.join() 返回的路径必须已经包含路径的转义版本。当我在函数load_modules_from_dir 中打印参数dirname 时,我得到:H:\temp\linx\dist\calibrate\dcljscal 而不是H: emp\linx\dist\calibrate\dcljscal。现在的问题是为什么它在pkgutil.iter_modules() 中不起作用?
  • os.path.join(os.path.dirname(__file__)) 没有意义。使用os.path.abspath(os.path.dirname(__file__))
  • @eryksun os.path.join()os.path.abspath() 在我的系统上给出相同的结果。谢谢你的帮助。你用\t 为我指明了正确的方向。
  • 是的,但是加入一个字符串的路径来创建绝对路径并不是os.path.join 的预期效果。使用显然是为你想做的事情而设计的功能。不要依赖无关函数的副作用。

标签: python windows python-2.7 path-separator


【解决方案1】:

简短的回答是:这个问题没有答案。表示路径名的字符串总是可以包含特殊字符,这些字符随时会咬你。

有很多 SE 帖子试图给出解决方案。他们中的大多数修复了一个特殊情况,一般不工作。关于什么是最好的方法没有达成共识。请参阅:
- Unpredictable results from os.path.join in windows
- Python windows path slash
- Path Separator in Python 3
- Windows path in python
- mixed slashes with os.path.join on windows
- Why not os.path.join use os.path.sep or os.sep?

这篇博文也值得一提,因为作者使用了一种略有不同的方法来表达他的观点:backslashes-in-windows-filenames

处理路径名的一种实用方法是将 Windows 路径分隔符替换为 Linux 分隔符:path_name = path_name.replace('\\', '/')
Windows XP 和更高版本的 Windows 上的 Python 使用 C:/tab/newline/return/012/x012 没有问题。

只有当您必须打印或记录路径时,您才可以使用os.path.normpath() 将路径转换为您运行 Python 的操作系统或平台的表示形式。

【讨论】:

  • 如果os.path.abspath(os.path.dirname(__file__)) 生成的文件路径以某种方式将\t 重新解释为选项卡,那将是一个非常糟糕的错误。通常只有 compilerstring literals 执行此操作。
  • 你不能总是用斜杠代替反斜杠。以\\?\ 为前缀的扩展路径需要反斜杠。此前缀绕过正常路径处理,以超过 260 个字符的路径限制。 Windows 所做的只是在进行系统调用之前将\\?\ 替换为NT DOS 设备前缀\??\,并且在NT 内核命名空间中,只有反斜杠 是路径分隔符。此外,如果您正在创建命令行以使用子进程运行另一个程序,该程序可能会将斜杠视为选项开关。
猜你喜欢
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 2014-09-27
  • 2021-04-02
  • 2021-05-27
  • 2018-03-20
  • 2011-06-05
  • 1970-01-01
相关资源
最近更新 更多