2017-03-17 55 views
2

我试图创建一个函数,它接受多个参数,并返回一个可调用的lambda函数。我将这些lambda函数传递到BeautifulSoup的find_all方法中以解析html。返回动态创建函数

这里是我写生成lambda函数功能:

def tag_filter_function(self, name="", search_terms={}, attrs=[], **kwargs): 

    # filter attrs that are in the search_terms keys out of attrs 
    attrs = [attr for attr in attrs if attr not in search_terms.keys()] 

    # array of strings to compile into a lambda function 
    exec_strings = [] 

    # add name search into exec_strings 
    if len(name) > 0: 
     tag_search_name = "tag.name == \"{}\"".format(name) 
     exec_strings.append(tag_search_name) 

    # add generic search terms into exec_strings 
    if len(search_terms) > 0: 
     tag_search_terms = ' and '.join(["tag.has_attr(\"{}\") and tag[\"{}\"] == \"{}\"".format(k, k, v) for k, v in search_terms.items()]) 
     exec_strings.append(tag_search_terms) 

    # add generic has_attr calls into exec_strings 
    if len(attrs) > 0: 
     tag_search_attrs = ' and '.join(["tag.has_attr(\"{}\")".format(item) for item in attrs]) 
     exec_strings.append(tag_search_attrs) 

    # function string 
    exec_string = "lambda tag: " + " and ".join(exec_strings) 

    return exec(compile(exec_string, '<string>', 'exec')) 

从调用

tag_filter_function(name="article", search_terms={"id" : "article"}) 

的函数返回的字符串是

lambda tag: tag.name == "article" and tag.has_attr("id") and tag["id"] == "article" 

函数的返回值是None。我不确信exec()函数是我想在这里使用的,但我真的不确定。将该字符串转换为可执行的lambda函数是可能的,如果是这样的话?不知道我是否以正确的方式开展这项工作。

+0

如果你使用'标签上has_attr',你不应该找'tag.attr '而不是'tag [attr]'? –

回答

5

绝对不需要使用exec。要从一个函数返回一个函数,只需定义一个新函数并返回它。例如。

def outer_function(): 
    def inner_function(): 
     something_here 
    return inner_function 

在你的情况下,它看起来像你想要做这样的事情:

def tag_filter_function(self, name="", search_terms={}, attrs=[], **kwargs): 

    # filter attrs that are in the search_terms keys out of attrs 
    attrs = [attr for attr in attrs if attr not in search_terms.keys()] 

    def f(tag): 

     # add name search into exec_strings 
     if len(name) > 0: 
      if tag.name != name: 
       return False 

     # add generic search terms into exec_strings 
     if len(search_terms) > 0: 
      if not all(tag.has_attr(k) and tag[k] == v 
        for k, v in search_terms.items()): 
       return False 

     # add generic has_attr calls into exec_strings 
     if len(attrs) > 0: 
      if not all(tag.has_attr(item) for item in attrs): 
       return False 

     return True 

    return f 
+2

人们有不同的喜好,但我认为'functools.partial'比嵌套功能的效果更好。 – DSM

+0

@DSM是的,如果你真的想避免嵌套,'functools.partial'会是一个有趣的方法。它确实有一些好处,比如只有一个“内部”函数实例,但我喜欢嵌套:) – zvone

+0

很好的答案(我的意图是解决OP的具体问题,而你的更好,因为它教育更好的方法这个问题一起)。我想你可能想要编辑你的答案,使得返回的函数依赖于OP所要求的参数'tag'。 –

-2

如果你想最小的改变你的代码,你可以简单地尝试:

return eval(exec_string) 

但对于一个更好的方法来解决你的问题,你应该遵循zvone的建议和完全重新制订的办法通过返回一个函数。