2012-06-20 18 views
11

,bir dizeden bir lamda işlevi oluşturun ** düzgün ** Böyle bir dize</p> <pre><code>"2*(i+j) <= 100" </code></pre> <p>Ben tekabül lambda fonksiyonu oluşturmak istiyorum Verilen

fn = lambda i,j: 2*(i+j) <= 100 
  • Yapabileceğim bu eval ile, ancak daha az kötü bir yöntem arıyorum.

  • Ben

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

    bulduk ama sonuç yürütmek için nasıl anlamaya değil!

  • İdeal olarak, otomatik olarak parametre listesini ('i', 'j') de otomatik olarak çıkarmak istiyorum - şu an sadece re.findall ('\ w +') kullanıyordum, ama ben isterim 'Anahtar Kelimeler' olarak gölgelemek yerine cos gibi mevcut işlevleri düzgün kullanabilmek.


Ben Is there a Python library for handling complicated mathematical sets (constructed using mathematical set-builder notation)? bakarak ve en iyi kısıt-çözücüye beslemek için lambdas içine küme yapım notasyonu ayrıştırmak anlamaya çalışıyordum.

Temel olarak değişkenleri tanıyacak olan ast.literal_eval için diliyorum.

İdeal olarak, geri Sonra constraint doğrudan yem olabilir ((lambda x: x >= 20), ['i']) almak istiyorum i >= 20 verilen.

+0

Çözmeyi denediğiniz problem nedir? Bir gp okuma-yorumlama döngüsü mi yapıyorsunuz? – starbolin

cevap

2

tutun. girişinizi güvenilmeyen ise

, o zaman sterilize olması gerekiyor.

Bir makul yaklaşım regex kullanılmasıdır. Dizede işlev çağrıları, özellik aramaları veya çift alt çizgiler olmadığından emin olun. Alternatif olarak, daha karmaşık bir yaklaşım, AST ayrıştırma ağacında herhangi bir sakıncalı çağrı olup olmadığını belirlemek için yürümektir.

üçüncü bir yaklaşım AST ayrıştırma ağacı yürümek ve doğrudan yürütmektir. Bu size çağrıların ne olduğu konusunda tam bir kontrol sağlar. Ast.literal_eval işlevi bu yaklaşımı alır.Belki de kaynağından başlayıp destek olmak istediğiniz herhangi bir işlem için bazı geliştirmeler yapın:

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

eval'a bir alternatif mi arıyorsunuz, ama neden? Rasgele kod kabul ediyor ve yine de yürütüyorsunuz, neden eval'u kullanmıyorsunuz? eval'dan kaçınmanın tek sebebi tehlikeli olduğu için, yarattığınız lambda kadar tehlikeli olacaktır. girişinizi eval() gitmek en net, en kolay ve en güvenilir yoludur, bir güvenilir bir kaynaktan geliyorsa

Ayrıca, akılda you really can't make it safe to do this in CPython

+4

** Yapılamadı **, nadiren Python'a uygulanan bir ifadedir. * Ast.literal_eval * işlevi, neyi kabul edebileceğinizi sınırlarken, keyfi kodun nasıl değerlendirileceğinin güzel bir örneğidir. Ayrıca, eğer OP * güvenilir * giriş ile çalışıyorsa, o zaman * eval * veya * exec * mükemmeldir (Guido bunları örneğin * timeit * modülünde kullanır). –

+1

'ast.literal_eval', OP’in sorunu için uygun değildir, çünkü bunlarda değerlendirmeyle ifadeler istiyor. Buradaki amacım, devam etmek ve 'eval'ı kullanmaktır. Bu tehlikeli bir şeydir, ancak asıl hedefi de bu yüzden başka herhangi bir yöntem aynı derecede tehlikeli olacaktır. –

+0

Güzel blog yazısı. – dreftymac

İlgili konular