2012-06-20 16 views
11

Biorąc pod uwagę ciąg takich jakutworzyć funkcję lambda z ciągiem ** prawidłowo **

"2*(i+j) <= 100" 

Chcę, aby wygenerować odpowiednią funkcję lambda,

fn = lambda i,j: 2*(i+j) <= 100 
  • mogę to zrobić z eval, ale szukam mniej złej metody.

  • znalazłem

    import ast 
    f = ast.Lambda('i,j', '2*(i+j) <= 100') 
    

    ale ja nie dowiedzieć się, jak wykonać wynik!

  • Idealnie chciałbym również automatycznie wyciągnąć listę parametrów ("i", "j") - w tej chwili używam tylko re.findall ('\ w +'), ale chciałabym być w stanie właściwie wykorzystać istniejące funkcje, takie jak cos zamiast cienia ich jako "słów kluczowych".


Szukałem na Is there a Python library for handling complicated mathematical sets (constructed using mathematical set-builder notation)? i próbuje dowiedzieć się, jak najlepiej przeanalizować zapis zestaw budowniczy do lambdas karmić przy ograniczeniu-solver.

Po prostu pragnę dla ast.literal_eval, który rozpoznałby również zmienne.

Idealnie, biorąc pod uwagę i >= 20 Chciałbym odzyskać ((lambda x: x >= 20), ['i']), który mógłbym następnie karmić bezpośrednio do constraint.

+0

Na czym polega problem, który próbujesz rozwiązać? Czy tworzysz pętlę do odczytu i interpretacji gp? – starbolin

Odpowiedz

2

Jeśli wejście jest z zaufanego źródłaThe eval() to najprostszy, najczystszych i najbardziej niezawodny sposób, aby przejść.

Jeśli twoje dane wejściowe to niezaufane, to musi być odkażona.

Jednym rozsądnym podejściem jest użycie wyrażeń regularnych. Upewnij się, że w ciągu znaków nie ma wywołań funkcji, wyszukiwań atrybutów ani podwójnych podkreśleń.

Alternatywnie, bardziej wyrafinowanym podejściem jest posłużenie się drzewem analizy AST w celu ustalenia, czy istnieją jakieś kontrowersyjne połączenia.

Trzecim podejściem jest chodzenie po drzewie analizy AST i wykonywanie go bezpośrednio. To daje ci całkowitą kontrolę nad tym, co dostaje połączenia. Funkcja ast.literal_eval przyjmuje takie podejście.Być może zacznij od źródła i wykonaj kilka kompilacji dla operacji, które chcesz obsłużyć:

def literal_eval(node_or_string): 
    """ 
    Safely evaluate an expression node or a string containing a Python 
    expression. The string or node provided may only consist of the following 
    Python literal structures: strings, numbers, tuples, lists, dicts, booleans, 
    and None. 
    """ 
    _safe_names = {'None': None, 'True': True, 'False': False} 
    if isinstance(node_or_string, basestring): 
     node_or_string = parse(node_or_string, mode='eval') 
    if isinstance(node_or_string, Expression): 
     node_or_string = node_or_string.body 
    def _convert(node): 
     if isinstance(node, Str): 
      return node.s 
     elif isinstance(node, Num): 
      return node.n 
     elif isinstance(node, Tuple): 
      return tuple(map(_convert, node.elts)) 
     elif isinstance(node, List): 
      return list(map(_convert, node.elts)) 
     elif isinstance(node, Dict): 
      return dict((_convert(k), _convert(v)) for k, v 
         in zip(node.keys, node.values)) 
     elif isinstance(node, Name): 
      if node.id in _safe_names: 
       return _safe_names[node.id] 
     elif isinstance(node, BinOp) and \ 
      isinstance(node.op, (Add, Sub)) and \ 
      isinstance(node.right, Num) and \ 
      isinstance(node.right.n, complex) and \ 
      isinstance(node.left, Num) and \ 
      isinstance(node.left.n, (int, long, float)): 
      left = node.left.n 
      right = node.right.n 
      if isinstance(node.op, Add): 
       return left + right 
      else: 
       return left - right 
     raise ValueError('malformed string') 
    return _convert(node_or_string) 
14

Poszukujesz alternatywy dla eval, ale dlaczego? Akceptujesz dowolny kod i mimo to go wykonujesz, więc dlaczego nie skorzystać z eval? Jedynym powodem, dla którego należy unikać eval jest to, że jest to niebezpieczne, ale lambda, którą stworzysz, będzie równie niebezpieczna.

Ponadto, należy pamiętać, you really can't make it safe to do this in CPython

+4

** Nie można tego dokonać ** to wyrażenie, które rzadko odnosi się do Pythona. Funkcja * ast.literal_eval * jest świetnym przykładem tego, jak oceniać dowolny kod, a jednocześnie ograniczać to, co możesz zaakceptować. Ponadto, jeśli OP działa z * zaufanym * wejściem, wtedy * eval * lub * exec * jest całkowicie uzasadnione (Guido używa ich w module * timeit * na przykład). –

+1

'ast.literal_eval' nie nadaje się do problemu PO, ponieważ chce wyrażenia z oceną w nich. Chodzi mi o to, aby iść dalej i używać 'eval', jest to niebezpieczne, ale tak samo jest jego faktycznym celem, więc każda inna metoda będzie równie niebezpieczna. –

+0

Ładny blog. – dreftymac

Powiązane problemy