2016-09-02 99 views
0

我想要做的事,如:喜欢的东西ast.literal_eval执行变量赋值

import ast 

def foo(common_stuff, assignment_str): 
    common_stuff() 
    ast.literal_eval(assignment_str) # assignment to unknown or passed variable 

foo('a=1;b=2') 

这可能在Python?

我试图写一个通用功能(执行DRY)本:

for f, i in zip(task_set, xrange(len(task_set))): 
     cd = f.cleaned_data 
     t_name = cd.get('t_name') 
     start_date = cd.get('start_date') 
     end_date = cd.get('end_date') 
     project = Project.objects.get(pro_id=p.pro_id) 
     task = Task(t_name=t_name, start_date=start_date, 
        end_date=end_date, project=project) 
     task.save() 
     tasks_list.append(task) 

于是我开始写如下:

def save_form(model, formset, foreignkey_assignment, *args){ 
    for f, i in zip(formset, xrange(len(formset))): 
     cd = f.cleaned_data 
     get_key_name = lambda x: cd.get(x) 
     ast.literal_eval(foreignkey_assignment) 
     m = model(**{k:get_key_name(k) for k in args}) 
     m.save() 
} 
+0

如果你已经有了需要在'* args'中获得的键列表,为什么你需要用'literal_eval'赋值? – Kevin

回答

2

ast.literal_eval()'执行'评估的AST分析树,并将其限制为仅允许标准Python文本的严格子集。您可以采取source code并添加分配支持(我将使用单独的字典来处理名称)。

你不得不添加AssignName节点处理(Python 3的版本):

def literal_eval(node_or_string, namespace): 
    """ 
    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, bytes, numbers, tuples, lists, dicts, 
    sets, booleans, and None. 
    """ 
    if isinstance(node_or_string, str): 
     node_or_string = ast.parse(node_or_string, mode='exec') 
    if isinstance(node_or_string, ast.Module): 
     node_or_string = node_or_string.body 
    def _convert(node, ns=None): 
     if isinstance(node, (ast.Str, ast.Bytes)): 
      return node.s 
     elif isinstance(node, ast.Num): 
      return node.n 
     elif isinstance(node, ast.Tuple): 
      return tuple(map(_convert, node.elts)) 
     elif isinstance(node, ast.List): 
      return list(map(_convert, node.elts)) 
     elif isinstance(node, ast.Set): 
      return set(map(_convert, node.elts)) 
     elif isinstance(node, ast.Dict): 
      return dict((_convert(k), _convert(v)) for k, v 
         in zip(node.keys, node.values)) 
     elif isinstance(node, ast.NameConstant): 
      return node.value 
     elif isinstance(node, ast.UnaryOp) and \ 
      isinstance(node.op, (ast.UAdd, ast.USub)) and \ 
      isinstance(node.operand, (ast.Num, ast.UnaryOp, ast.BinOp)): 
      operand = _convert(node.operand) 
      if isinstance(node.op, ast.UAdd): 
       return + operand 
      else: 
       return - operand 
     elif isinstance(node, ast.BinOp) and \ 
      isinstance(node.op, (ast.Add, ast.Sub)) and \ 
      isinstance(node.right, (ast.Num, ast.UnaryOp, ast.BinOp)) and \ 
      isinstance(node.left, (ast.Num, ast.UnaryOp, ast.BinOp)): 
      left = _convert(node.left) 
      right = _convert(node.right) 
      if isinstance(node.op, ast.Add): 
       return left + right 
      else: 
       return left - right 
     elif isinstance(node, ast.Assign) and \ 
      len(node.targets) == 1 and \ 
      isinstance(node.targets[0], ast.Name): 
       assert isinstance(ns, dict) # will be None when not top-level 
       ns[node.targets[0].id] = _convert(node.value) 
       return 
     raise ValueError('malformed node or string: ' + repr(node)) 
    return _convert(node_or_string, namespace) 

或者你可以使用asteval project,这不正是这一点,多一点,支持简单的表达式和赋值,使用AST树解释。