对python os.path.abspath的误解

Misunderstanding of python os.path.abspath

我有以下代码:

1
2
3
directory = r'D:\images'
for file in os.listdir(directory):
    print(os.path.abspath(file))

我想要下一个输出:

  • D:图像img1.jpg
  • D:imagesimg2.jpg等

但我得到了不同的结果:

  • D:代码img1.jpg
  • D:代码img2.jpg

其中d:code是我当前的工作目录,结果与

1
os.path.normpath(os.path.join(os.getcwd(), file))

所以,问题是:os.path.abspath的目的是什么,而我必须使用

1
os.path.normpath(os.path.join(directory, file))

要得到我文件的真正绝对路径吗?如果可能,显示真实的用例。


问题在于你对os.listdir()的理解,而不是os.path.abspath()的理解。os.listdir()返回目录中每个文件的名称。这将给您:

1
2
3
img1.jpg
img2.jpg
...

当你把它们传递给os.path.abspath()时,它们被视为相对路径。这意味着它是相对于执行代码的目录的。这就是为什么你会得到"d:codeimg1.jpg"。

相反,您要做的是将文件名与所列出的目录路径连接起来。

1
os.path.abspath(os.path.join(directory, file))

listdir生成目录中的文件名,而不引用目录本身的名称。在没有任何其他信息的情况下,abspath只能从它能知道的唯一目录(当前工作目录)形成绝对路径。您可以在循环之前更改工作目录:

1
2
3
os.chdir(directory)
for f in os.listdir('.'):
    print(os.path.abspath(f))


python的本地os.listdiros.path函数的级别非常低。迭代一个目录(或一系列降序目录)需要程序手动组装文件路径。可以方便地定义一个实用程序函数,该函数生成您只需要一次的路径,这样就不必在每次目录迭代中重复路径组装逻辑。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import os

def better_listdir(dirpath):
   """
    Generator yielding (filename, filepath) tuples for every
    file in the given directory path.
   """

    # First clean up dirpath to absolutize relative paths and
    # symbolic path names (e.g. `.`, `..`, and `~`)
    dirpath = os.path.abspath(os.path.expanduser(dirpath))

    # List out (filename, filepath) tuples
    for filename in os.listdir(dirpath):
        yield (filename, os.path.join(dirpath, filename))

if __name__ == '__main__':
    for fname, fpath in better_listdir('~'):
        print fname, '->', fpath

或者,也可以使用"更高级别"的路径模块,例如py.path、path.py和pathlib(现在是python的标准部分,用于3.4及以上版本,但可用于2.7 forward)。这些增加了项目的依赖性,但提高了文件、文件名和文件路径处理的许多方面。