【问题标题】:'tuple' object has no attribute 'replace'“元组”对象没有“替换”属性
【发布时间】:2018-10-13 13:53:10
【问题描述】:

我已经浏览了有关此错误的先前帖子。但是,这对我没有帮助。所以我重新提请注意。代码如下。

import os
replacements = {':': '_', '+': '_'}

for fn in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'):
    nn = fn
    for k, v in replacements.items():
        nn = nn.replace(str(k), str(v))
        if nn != fn:
             os.rename(fn, nn)

这在运行时会出现错误'tuple' object has no attribute 'replace',并且似乎会出现错误。我正在使用 dict 替换文件名中的特殊字符,例如[,&<>*?|\";+:'() ]。有没有更好的方法来做到这一点。谢谢。

【问题讨论】:

    标签: python string replace filenames os.walk


    【解决方案1】:

    os.walk 产生元组:

    对于树中的每个目录 目录顶部(包括顶部本身),它产生一个 3 元组(目录路径, 目录名、文件名).

    要仅提取文件名,请使用索引或序列解包。其中任何一个都可以:

    nn = fn[-1]
    nn = fn[2]
    _, _, nn = fn
    

    或者,正如@AntonvBR 指出的那样,您可以在for 循环迭代的定义中使用序列解包:

    for _, _, fn in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'):
        nn = fn
        # as before..
    

    【讨论】:

    • 是的,也很好解释。但是,它会更 Pythonic,我知道您同意更改这一行 for fn in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'),而不是添加一个新变量(例如 _、_、nn)。
    • @AntonvBR,好点,谢谢。已使用该选项进行了更新。
    【解决方案2】:

    在您的第一段代码中,fn 是一个元组,因为os.walk() 返回一个由 dirpath(字符串)、dirnames(列表)、文件名(list)组成的元组。因此,当将其分配给nn 时,nn 成为元组,而反过来使用nn.replace(k, v) 将不起作用,因为元组没有方法replace

    在您的第二段代码中,nn 现在等于fn[2](目录名列表)。不幸的是,列表也没有replace 方法。假设您要替换文件名中的所有 :+,那么您需要遍历每个文件名:

    我在代码中观察和更改的其他内容:

    • os.walk 返回的文件名不包含文件的完整路径,这意味着如果脚本不在与您正在重命名文件的目录相同的目录中运行,os.rename 可能找不到该文件。所以我在重命名时也加入了path
    • os.rename 之后,目录中的文件将被重命名,但代码读取的文件名仍然相同。因此,您还必须更改代码中的文件名。

    所以:

    import os
    replacements = {':': '_', '+': '_'}
    
    for fn in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'):
        path = fn[0]
        nn = fn[2]
        for filename in nn:
            newname = filename
            for k, v in replacements.items():
                newname = newname.replace(str(k), str(v))
                if newname != filename:
                     os.rename(os.path.join(path, filename), os.path.join(path, newname))
                     filename = newname
    

    虽然我会通过以下建议再删减一行代码:

    import os
    replacements = {':': '_', '+': '_'}
    
    for path, _, filenames in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'):
        for filename in filenames:
            newname = filename
            for k, v in replacements.items():
                newname = newname.replace(k, v)
                if newname != filename:
                     os.rename(os.path.join(path, filename), os.path.join(path, newname))
                     filename = newname
    

    【讨论】:

    • 通过复制粘贴运行它会出现FileNotFoundError: [Errno 2] No such file or directory: ....
    • 我已经提出了重新编码行的请求,请参阅。
    • @ambrishdhaka 你为什么不在fn 上循环播放?您只重命名编辑代码中文件列表中的第二个文件,这就是第二次重命名的原因。但这也让我意识到一个问题。我已经编辑了我的答案,以便文件名也可以在代码中重命名。
    • 如果我完全复制粘贴您的代码,我会收到此错误FileNotFoundError: [Errno 2] No such file or directory: 'SIPRI_military......
    • 您看到奇怪行为的原因是文件名被重命名,而不是代码中的文件名字符串。这就是我在之前的编辑之一中插入filename = newname 的原因。
    【解决方案3】:

    问题是线

    nn = nn.replace(str(k), str(v))
    

    os.walk根据the Python docs返回(dirpath, dirnames, filenames)形式的元组序列。所以你试图在一个元组上调用.replace() 方法,这会给你一个错误,因为tuple 类没有这样的方法。我假设您打算使用 str.replace() 方法。

    这里有一些应该可以工作的代码(在我在我的机器上为此目的创建的一些目录上测试过):

    import os
    replacements = {':': '_', '+': '_'}
    
    for directory in os.walk('/media/ambijat/Dataworld/f23/Dropbox/ttgis'):
        filenames = directory[-1]
    
        for k, v in replacements.items():
    
            for filename in filenames:
                newname = filename.replace(k, v)
    
                if newname != filename:
                    os.rename(directory[0]+'\\'+filename, directory[0]+'\\'+newname)
    

    【讨论】:

    • 我只能感觉到您的部分解释,但如何进入代码距离我只有几英里之遥。如果您能提供一些代码行替换,将不胜感激。
    • @ambrishdhaka 我现在已经在我的答案中添加了更多细节,我希望这会有所帮助。另外我建议参考上面的答案,它提供了替代解决方案。
    • 我按照上面的代码应用了修改。 replace 现在给出的是列表而不是元组。错误保持不变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-26
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 2022-01-21
    • 2013-06-21
    相关资源
    最近更新 更多