返回动态创建的函数

时间:2017-03-17 00:01:01

标签: python lambda beautifulsoup

我正在尝试创建一个带有多个参数的函数,并返回一个可调用的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函数,如果是这样的话?不确定我是否正确地采取了这种方式。

2 个答案:

答案 0 :(得分:5)

绝对没有必要使用exec。要从函数返回函数,只需定义一个新函数并将其返回。 E.g。

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

答案 1 :(得分:-2)

如果您想对代码进行最小的更改,可以尝试:

return eval(exec_string)

但是为了更好地解决问题,你应该遵循zvone的建议,并通过返回一个函数来完全重新制定方法。