我制作了一个从HTML文件中提取文本的程序。它递归HTML文档并返回标记列表。例如,
输入< li>没有办法< b>你< / b>这样做< / li>
输出 ['不','方式','你','是'......] 。
这是一个高度简化的伪代码:
def get_leaves(node):
kids=getchildren(node)
for i in kids:
if leafnode(i):
get_leaves(i)
else:
a=process_leaf(i)
list_of_leaves.append(a)
def calling_fn():
list_of_leaves=[] #which is now in global scope
get_leaves(rootnode)
print list_of_leaves
我现在正在使用来自调用函数的全局范围 list_of_leaves 。 calling_fn()声明了这个变量,get_leaves()追加到这个变量。
我的问题是,如何修改我的功能,以便能够执行类似list_of_leaves = get_leaves(rootnode)的操作,即不使用全局变量?
我不希望函数的每个实例都复制列表,因为列表可能会变得非常大。
请不要批评这个特定伪代码的设计,因为我简化了这一点。它用于另一个目的:使用BeautifulSoup
提取令牌以及相关标签答案 0 :(得分:11)
您可以将结果列表作为可选参数传递。
def get_leaves(node, list_of_leaves=None):
list_of_leaves = [] if list_of_leaves is None else list_of_leaves
kids=getchildren(node)
for i in kids:
if leafnode(i):
get_leaves(i, list_of_leaves)
else:
a=process_leaf(i)
list_of_leaves.append(a)
def calling_fn():
result = []
get_leaves(rootnode, list_of_leaves=result)
print result
Python对象总是通过引用传递。这已在here之前讨论过。一些内置类型是不可变的(例如int
,string
),因此您无法在适当的位置修改它们(当您连接两个字符串并将它们分配给变量时会创建一个新字符串)。可以在适当的位置修改可变类型的实例(例如list
)。我们通过在递归调用中传递原始列表来累积结果来利用这一点。
要在真实应用程序中从HTML中提取文本,使用像BeautifulSoup
或lxml.html
这样的成熟库总是一个更好的选择(正如其他人所建议的那样)。
答案 1 :(得分:8)
如果将get_leaves()
转换为生成器,则无需将累加器传递给函数或通过全局名称访问它:
def get_leaves(node):
for child in getchildren(node):
if leafnode(child):
for each in get_leaves(child):
yield each
else:
yield process_leaf(child)
def calling_fn():
list_of_leaves = list(get_leaves(rootnode))
print list_of_leaves
答案 2 :(得分:2)
使用像BeautifulSoup这样不错的HTML解析器,而不是尝试比现有软件更聪明。
答案 3 :(得分:2)
@pillmincher的生成器答案是最好的,但作为另一种选择,你可以将你的功能变成一个类:
class TagFinder:
def __init__(self):
self.leaves = []
def get_leaves(self, node):
kids = getchildren(node)
for i in kids:
if leafnode(i):
self.get_leaves(i)
else:
a = process_leaf(i)
self.list_of_leaves.append(a)
def calling_fn():
finder = TagFinder()
finder.get_leaves(rootnode)
print finder.list_of_leaves
您的代码可能还涉及许多辅助函数,例如leafnode
,因此一个类也可以帮助将它们组合成一个单元。
答案 4 :(得分:0)
作为关于递归的一般问题,这是一个很好的问题。通常有一个递归函数将数据累积到某个集合中。要么集合需要是全局变量(坏),要么将传递给递归函数。当几乎每种语言都传递集合时,只传递一个引用,因此您不必担心空间。有人刚刚发布了一个答案,显示了如何做到这一点。