【问题标题】:Making a program recursively call itself in Python使程序在 Python 中递归调用自身
【发布时间】:2015-02-10 04:01:44
【问题描述】:

我写了一个简单的脚本,它在一个文件夹上运行,会循环遍历一个文件夹中的所有文件来做一些处理(实际处理不重要)。

我有一个文件夹。此文件夹包含多个不同的文件夹。在这些文件夹中是可变数量的文件,我想在这些文件上运行我编写的脚本。我正在努力调整我的代码来做到这一点。

所以之前的文件结构是:

Folder
  Html1
  Html2
  Html3
  ...

现在是:

Folder
  Folder1
    Html1
  Folder2
    Html2
    Html3

我仍然想在所有 HTML 上运行代码。

这是我这样做的尝试,结果是

error on line 25, in CleanUpFolder
    orig_f.write(soup.prettify().encode(soup.original_encoding))
TypeError: encode() argument 1 must be string, not None

def CleanUpFolder(dir):
    do = dir
    dir_with_original_files = dir
    for root, dirs, files in os.walk(do):
        for d in dirs:
            for f in files:
                print f.title()
                if f.endswith('~'): #you don't want to process backups
                    continue
                original_file = os.path.join(root, f)
                with open(original_file, 'w') as orig_f, \
                    open(original_file, 'r') as orig_f2:
                    soup = BeautifulSoup(orig_f2.read())
                    for t in soup.find_all('td', class_='TEXT'):
                        t.string.wrap(soup.new_tag('h2'))

                # This is where you create your new modified file.
                    orig_f.write(soup.prettify().encode(soup.original_encoding))

CleanUpFolder('C:\Users\FOLDER')

我在这里错过了什么?我不确定的主要是这条线如何

    for root, dirs, files in os.walk(do):

在这种情况下被使用/理解了吗?

【问题讨论】:

  • 您不需要递归调用,这就是 os.walk 的用途。回到基础;只需运行 for root, dirs, files in os.walk(do): print root, dirs, files 看看会发生什么。
  • 除非您在实际代码中转义路径,否则传递给函数的路径实际上是:C:sersolder。确保转义路径 'C:\\Users\\FOLDER' 或使用原始字符串 r'C:\Users\FOLDER'。此外,函数名称不应以大写字母开头,因为其他人看到它会认为它是 class 而不是 function
  • 另外,FWIW 您的错误(“第 25 行的错误,在 CleanUpFolder”)显然与递归无关(“显然”对于花费几秒钟实际阅读错误消息的人来说,在最少)。
  • 这与整洁无关;如果你 walk 并在 dirs 上递归调用 CleanUpFolder,则在深度 n 的目录中清理它 2 ** n 次!
  • 仍然是“真正的”错误:soup.prettify().encode("some-encoding-here") 不会完全按照您的意愿行事:它确实会将soup.prettify() 的结果编码为您传递的任何编码,但是您的 html“内容类型”元数据中声明了错误的编码,参见 crummy.com/software/BeautifulSoup/bs4/doc/#output-encoding。你想要'soup.prettify("some-encoding-here"),然后不需要.encode()结果。

标签: python oop python-2.7 python-3.x recursion


【解决方案1】:

在这里,我将您的函数拆分为两个单独的函数并清除了冗余代码:

def clean_up_folder(dir):
    """Run the clean up process on dir, recursively."""
    for root, dirs, files in os.walk(dir):
        for f in files:
            print f.title()
            if not f.endswith('~'): #you don't want to process backups
                clean_up_file(os.path.join(root, f))

这已经解决了缩进问题,并将更容易测试功能并隔离任何未来的错误。我还删除了dirs 上的循环,因为无论如何这都会在walk 内发生(这意味着您将跳过任何不包含任何子dirsdir 中的所有files)。

def clean_up_file(original_file):
    """Clean up the original_file."""      
    with open(original_file) as orig_f2:
        soup = BeautifulSoup(orig_f2.read())
    for t in soup.find_all('td', class_='TEXT'):
        t.string.wrap(soup.new_tag('h2'))
    with open(original_file, 'w') as orig_f:
        # This is where you create your new modified file.
        orig_f.write(soup.prettify().encode(soup.original_encoding))

请注意,我已将 original_file 的两个 opens 分开,因此您在读取之前不会意外覆盖它 - 无需同时打开它以进行读取和写入。

我没有在此处安装BeautifulSoup,因此无法进一步测试,但这应该可以让您将问题缩小到特定文件。

【讨论】:

  • 非常感谢您,非常感谢 :) 仍然遭受与 OP 相同的错误消息,但使用起来更干净、更好。谢谢。
  • @SimonKiely 这将使进行一些实际测试和查找错误变得更加容易,从而提出更好的问题。要问自己(或your duck)的明显问题包括:这是清理您期望的文件吗?这些文件是否包含您期望的内容? soup.find_all 能找到你所期望的吗?等等……
  • 如果soup.original_encoding 不是None:!!你太棒了@jonrsharpe,谢谢你:)
  • 非常感谢您耐心地向我解释我做错了什么,我觉得我从这篇文章中学到了很多东西——谢谢。
  • @SimonKiely 没问题。我认为你犯的关键错误不是代码的任何部分,而是试图一次将它们全部放在一起。分而治之 - 确定您的想法中可以分开的部分,并一次构建(和测试!)一个。在这里发现查找要清理的文件和清理它们可能是两个独立的过程,将复杂性降低了一半以上。
猜你喜欢
  • 2010-10-03
  • 2011-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-10
  • 2021-08-10
  • 1970-01-01
  • 2016-01-03
相关资源
最近更新 更多