2017-03-17 37 views
2

Ich versuche, eine Funktion zu erstellen, die mehrere Argumente und eine aufrufbare Lambda-Funktion zurückgibt. Ich übergebe diese Lambda-Funktionen in BeautifulSoup find_all Methode, um HTML zu analysieren.zurück dynamisch erstellte Funktion

Hier ist die Funktion, die ich geschrieben habe, die Lambda-Funktionen zu generieren:

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')) 

Die Funktion Zeichenfolge, die

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

zurück ist

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

Die Funktion der Rückkehr aus dem Aufruf Wert ist None. Ich bin nicht überzeugt, dass die exec() Funktion ist, was ich hier verwenden möchte, aber ich bin mir wirklich nicht sicher. Ist es möglich, diese Zeichenfolge in eine ausführbare Lambda-Funktion umzuwandeln, und wenn ja, wie? Ich bin mir nicht sicher, ob ich das richtig mache.

+0

Wenn Sie mit 'has_attr' auf dem Tag, sollten nicht Sie suchen nach' tag.attr 'anstatt' tag [attr] '? –

Antwort

5

Es ist absolut nicht notwendig, exec zu verwenden. Um eine Funktion von einer Funktion zurückzugeben, definieren Sie einfach eine neue Funktion und geben Sie sie zurück. Z.B.

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

In Ihrem Fall sieht es aus wie Sie, so etwas tun:

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

Die Leute haben andere Vorlieben, aber ich denke 'functools.partial' funktioniert sogar besser als Nesting-Funktionen. – DSM

+0

@DSM Ja, 'functools.partial' wäre ein interessanter Ansatz, wenn Sie die Verschachtelung wirklich vermeiden möchten. Und es hat einige Vorteile, wie nur eine Instanz der "inneren" Funktion, aber ich mag Verschachtelung :) – zvone

+0

Große Antwort (meins neigte, die spezifische Frage des OP zu lösen, während Sie besser ist, weil es über eine bessere Weise sich nähert, erzieht das Problem insgesamt). Ich denke, dass Sie Ihre Antwort möglicherweise bearbeiten möchten, um die zurückgegebene Funktion von einem Argument "tag" abhängig zu machen, wie das OP erfordert. –

-2

Wenn Sie die kleinste Änderung an Ihrem Code vornehmen möchten, können Sie einfach versuchen:

return eval(exec_string) 

aber für einen besseren Ansatz, Ihr Problem zu lösen, sollten Sie zvone Vorschlag und neu zu formulieren den Ansatz ganz folgen durch Rückgabe einer Funktion.

Verwandte Themen