【问题标题】:Why does root returned from os.walk() contain / as directory separator but os.sep (or os.path.sep) return \ on Win10?为什么从 os.walk() 返回的 root 包含 / 作为目录分隔符而 os.sep(或 os.path.sep)在 Win10 上返回 \?
【发布时间】:2020-07-29 20:21:56
【问题描述】:

为什么 os.walk() 返回的根元素显示 / 作为目录分隔符,而 os.sep (或 os.path.sep) 在Win10上显示\?

我只是想为文件夹中的一组文件创建完整路径,如下所示:

import os

base_folder = "c:/data/MA Maps"
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))

print(os.path.sep)

这是我得到的输出:

c:/data/MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:/data/MA Maps\Map_of_Massachusetts_Norfolk_County.png
\

我知道 python 的一些库函数(如 open()) 可以与混合路径分隔符一起使用(至少在 Windows 上),但依赖该 hack 确实不能在所有库中都得到信任.似乎从 os.walk()os.path.sep.join()) 应根据所使用的操作系统产生一致的结果。谁能解释为什么会发生这种不一致?

附: - 我知道有一个更一致的库用于处理文件路径(以及许多其他文件操作),称为 pathlib,它是在 python 3.4 中引入的,它似乎确实修复了这些所有。如果您的代码在 3.4 或更高版本中使用,是否最好使用 pathlib 方法来解决此问题?但是,如果您的代码针对使用 3.4 之前的 python 的系统,那么解决此问题的最佳方法是什么?

下面是 pathlib 的一个很好的基本解释:Python 3 Quick Tip: The easy way to deal with file paths on Windows, Mac and Linux

这是我使用 pathlib 的代码和结果:

import os
from pathlib import Path

# All of this should work properly for any OS. I'm running Win10.

# You can even mix up the separators used (i.e."c:\data/MA Maps") and pathlib still
# returns the consistent result given below.
base_folder = "c:/data/MA Maps" 

for root, dirs, files in os.walk(base_folder):
    # This changes the root path provided to one using the current operating systems
    # path separator (/ for Win10).
    root_folder = Path(root)
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
             # The / operator, when used with a pathlib object, just concatenates the
             # the path segments together using the current operating system path separator.
             print(root_folder / f)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

这甚至可以更简洁地使用 pathlib 和列表理解(每个操作系统正确处理所有路径分隔符):

from pathlib import Path

base_folder = "c:/data/MA Maps"
path = Path(base_folder)
files = [item for item in path.iterdir() if item.is_file() and 
                                            str(item).endswith(".png") and 
                                            (str(item).find("_N") != -1)]
for file in files:
    print(file)


c:\data\MA Maps\Map_of_Massachusetts_Nantucket_County.png
c:\data\MA Maps\Map_of_Massachusetts_Norfolk_County.png

这是非常 Pythonic 的,至少我觉得它很容易阅读和理解。 .iterdir() 真的很强大,它使处理文件和目录相当容易,并且以跨平台的方式。你怎么看?

【问题讨论】:

  • "...这是在 python 3.4 中引入的,它似乎确实解决了所有这些问题.." – 如果 Python 维护人员意识到这个问题并且 会怎样您正在寻找的解决方案?
  • 但这仍然使 os 和 path 不一致,至少据我所知 pathlib 并没有得到一致使用。大多数关于 Python 文件处理的培训只讨论使用操作系统和路径。
  • Windows 较晚出现,并为版权选择了不同的路径分隔符\ 。但它保持了 POSIX 兼容性,还允许 / 作为路径分隔符。您使用带有/ 的硬编码起始目录,但该目录使用操作系统标准\ 遍历添加的子目录。您可以规范化,获取硬编码起始目录的绝对路径。
  • 完全了解历史以及为什么存在 / 和 \ 的混合。但是不明白为什么 os 和 path 不能根据所使用的操作系统产生一致的结果。如图所示,pathlib 在幕后处理所有这些,并且始终提供具有正确结果的路径,而与所使用的操作系统无关。似乎 os 和 path 应该做同样的事情。
  • 似乎 root (从 os.walk() 返回)应该根据当前操作系统返回正确分离的根文件夹(不管 base_folder 路径如何分离)。如果这样做,那么 root 和 os.path.sep 将始终保持一致,并且您将始终确保您的路径独立于操作系统。我认为这种对 os 的更改不应该导致现有代码出现问题(但我可能会遗漏一些东西)。

标签: python python-3.x os.walk os.path path-separator


【解决方案1】:

os.walk 函数始终生成 dirpath 的初始部分,与您传递给它的内容相同。它不会尝试对分隔符本身进行规范化,它只是保留您给它的内容。它确实对路径的其余部分使用系统标准分隔符,因为它将每个子目录的名称与os.path.join 组合到根目录。可以看到os.walk函数in the CPython source repository的当前版本实现。

规范化输出中的分隔符的一个选项是规范化传递给os.walk 的基本路径,可能使用pathlib。如果您对初始路径进行规范化,则所有输出都应自动使用系统路径分隔符,因为它将是通过递归遍历保留的规范化路径,而不是非标准路径。这是您的第一个代码块的一个非常基本的转换,以使用 pathlib 规范化 base_folder,同时保留所有其余代码,简单。使用更多pathlib 的功能是否比您的版本更好,这是我将留给您的判断。

import os
from pathlib import Path

base_folder = Path("c:/data/MA Maps")    # this will be normalized when converted to a string
for root, dirs, files in os.walk(base_folder):
    for f in files:
        if f.endswith(".png") and f.find("_N") != -1:
            print(os.path.join(root, f))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-06
    • 2013-11-09
    • 2014-10-14
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    相关资源
    最近更新 更多