我们从Python开源项目中,提取了以下21个代码示例,用于说明如何使用ast.ListComp()。
def _get_offsets(func_ast): for arg in func_ast.args: start_line, start_col = arg.lineno - 2, arg.col_offset - 1 # horrible hack for http://bugs.python.org/issue31241 if isinstance(arg, (ast.ListComp, ast.GeneratorExp)): start_col -= 1 yield start_line, start_col for kw in func_ast.keywords: yield kw.value.lineno - 2, kw.value.col_offset - len(kw.arg) - 2
def visit_Call(self, node): if ( isinstance(node.func, ast.Name) and node.func.id == 'dict' and len(node.args) == 1 and not _has_kwargs(node) and isinstance(node.args[0], (ast.ListComp, ast.GeneratorExp)) and isinstance(node.args[0].elt, (ast.Tuple, ast.List)) and len(node.args[0].elt.elts) == 2 ): arg, = node.args key = Offset(node.func.lineno, node.func.col_offset) self.dicts[key] = arg self.generic_visit(node)
def visit_ListComp(self, node): # type: (ast.ListComp) -> None # 'listcomp' is the string literal used by python # to creating the SymbolTable for the corresponding # list comp function. self._handle_comprehension(node, 'listcomp')
def test_listcomp(self): self._simple_comp(ast.ListComp)
def visit_Call(self, node): if node.func.id not in GRP_FUNCS: return node else: self.generic_visit(node) return ast.Call( func=node.func, args=[ ast.ListComp( elt=node.args[0], generators=[ ast.comprehension( target=ast.Name(id="datarow", ctx=ast.Store(), lineno=0, col_offset=0), iter=ast.Name(id="data", ctx=ast.Load(), lineno=0, col_offset=0), ifs=[], lineno=0, col_offset=0 ) ], lineno=0, col_offset=0, ) ], keywords=[], ctx=ast.Load(), lineno=0, col_offset=0, )
def resolve_attr_id(node): if isinstance(node, (ast.Attribute, ast.Subscript)): value_id = None if isinstance(node.value, (ast.Name, ast.Attribute, ast.Subscript)): value_id = resolve_attr_id(node.value) elif isinstance(node.value, ast.Call): value_id = resolve_attr_id(node.value) elif isinstance(node.value, ast.Str): value_id = 'str' elif isinstance(node.value, ast.Bytes): value_id = 'bytes' elif isinstance(node.value, (ast.List, ast.ListComp)): value_id = 'list' elif isinstance(node.value, ast.Tuple): value_id = 'tuple' elif isinstance(node.value, (ast.Set, ast.SetComp)): value_id = 'set' elif isinstance(node.value, (ast.Dict, ast.DictComp)): value_id = 'dict' else: raise SyntaxError( 'unsupport type: {}'.format(ast.dump(node.value)) ) if isinstance(node, ast.Attribute): return '{}.{}'.format(value_id, node.attr) elif isinstance(node, ast.Subscript): slice = None if isinstance(node.slice.value, ast.Str): slice = node.slice.value.s elif isinstance(node.slice.value, ast.Num): slice = node.slice.value.n elif isinstance(node.slice.value, ast.Name): slice = resolve_attr_id(node.slice.value) return '{}[{}]'.format(value_id, slice) elif isinstance(node, ast.Call): return '{}()'.format(resolve_attr_id(node.func)) return node.id
def _find_true_position(self, node): """Return correct line number and column offset for a given node. This is necessary mainly because ListComp's location reporting reports the next token after the list comprehension list opening. Args: node: Node for which we wish to know the lineno and col_offset """ import re find_open = re.compile("^\s*(\\[).*$") find_string_chars = re.compile("['\"]") if isinstance(node, ast.ListComp): # Strangely, ast.ListComp returns the col_offset of the first token # after the '[' token which appears to be a bug. Workaround by # explicitly finding the real start of the list comprehension. line = node.lineno col = node.col_offset # loop over lines while 1: # Reverse the text to and regular expression search for whitespace text = self._lines[line-1] reversed_preceding_text = text[:col][::-1] # First find if a [ can be found with only whitespace between it and # col. m = find_open.match(reversed_preceding_text) if m: new_col_offset = col - m.start(1) - 1 return line, new_col_offset else: if (reversed_preceding_text=="" or reversed_preceding_text.isspace()): line = line - 1 prev_line = self._lines[line - 1] # TODO(aselle): # this is poor comment detection, but it is good enough for # cases where the comment does not contain string literal starting/ # ending characters. If ast gave us start and end locations of the # ast nodes rather than just start, we could use string literal # node ranges to filter out spurious #'s that appear in string # literals. comment_start = prev_line.find("#") if comment_start == -1: col = len(prev_line) -1 elif find_string_chars.search(prev_line[comment_start:]) is None: col = comment_start else: return None, None else: return None, None # Most other nodes return proper locations (with notably does not), but # it is not possible to use that in an argument. return node.lineno, node.col_offset
def _find_true_position(self, node): """Return correct line number and column offset for a given node. This is necessary mainly because ListComp's location reporting reports the next token after the list comprehension list opening. Args: node: Node for which we wish to know the lineno and col_offset """ import re find_open = re.compile("^\s*(\\[).*$") find_string_chars = re.compile("['\"]") if isinstance(node, ast.ListComp): # Strangely, ast.ListComp returns the col_offset of the first token # after the '[' token which appears to be a bug. Workaround by # explicitly finding the real start of the list comprehension. line = node.lineno col = node.col_offset # loop over lines while 1: # Reverse the text to and regular expression search for whitespace text = self._lines[line-1] reversed_preceding_text = text[:col][::-1] # First find if a [ can be found with only whitespace between it and # col. m = find_open.match(reversed_preceding_text) if m: new_col_offset = col - m.start(1) - 1 return line, new_col_offset else: if (reversed_preceding_text=="" or reversed_preceding_text.isspace()): line = line - 1 prev_line = self._lines[line - 1] # TODO(aselle): # this is poor comment detection, but it is good enough for # cases where the comment does not contain string literal starting/ # ending characters. If ast gave us start and end locations of the # ast nodes rather than just start, we could use string literal # node ranges to filter out spurious #'s that appear in string # literals. comment_start = prev_line.find("#") if comment_start == -1: col = len(prev_line) -1 elif find_string_chars.search(prev_line[comment_start:]) is None: col = comment_start else: return None, None # Most other nodes return proper locations (with notably does not), but # it is not possible to use that in an argument. return node.lineno, node.col_offset
def iter_expr_values(parent, node, child=None): """ Yield each value for *node* which can be tracked. Literals are returned as their evaluated value where as nodes which fail to evaluate to literals are returned as is. :param node parent: The parent node used to mark the start of the search path. :param node node: The target ast.Name node to find literal values for. :param node child: An optional child node to mark the end of the search path. """ child = child or node success, value = eval_ast.literal_expr(node) if success: yield value return if not isinstance(node, ast.Name): return test_nodes = collections.deque() def_nodes = get_definition_nodes(parent, node.id, child) for def_node_idx, def_node in enumerate(def_nodes): each = False next_node = (def_nodes[def_node_idx + 1] if len(def_nodes) > def_node_idx + 1 else child) src_node = None test_nodes.clear() if isinstance(def_node, ast.Assign): test_node = get_expr_value_src_dst(def_node.value, def_node.targets[0], node) if test_node: test_nodes.append(test_node) elif isinstance(def_node, ast.For): src_node = get_expr_value_src_dst(def_node.iter, def_node.target, node) each = node_is_child_of_parent(def_node.body, next_node) elif isinstance(def_node, ast.ListComp): for generator in def_node.generators: src_node = get_expr_value_src_dst(generator.iter, generator.target, node) if src_node: break if isinstance(src_node, (ast.List, ast.Tuple, ast.Set)): test_nodes.extend(src_node.elts if each else src_node.elts[-1:]) for test_node in test_nodes: success, value = eval_ast.literal_expr(test_node) if success: yield value continue for value in iter_expr_values(parent, test_node): success = True yield value if success: continue for def_node in get_definition_nodes(parent, test_node): for value in iter_expr_values(parent, def_node): success = True yield value yield test_node
def node_defines_name(node, name): """ Check if the specified statement node defines symbol *name*. :param node: The node to check. :param name: The symbol name to check. :return: Whether or not the node defines the symbole specified. :rtype: bool """ if isinstance(name, ast.Name): name = name.id if isinstance(node, ast.Assign): if node_targets_name(node, name): return True if isinstance(node.value, (ast.DictComp, ast.ListComp, ast.SetComp)): return node_defines_name(node.value, name) elif isinstance(node, ast.ClassDef): return node.name == name # these ones all assume the iterable will be executed at least once elif isinstance(node, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)): for generator in node.generators: target = generator.target if isinstance(target, ast.Name): if target.id == name: return True continue for child_node in iter_child_expr_nodes(target): if isinstance(child_node, ast.Name) and child_node.id == name: return True return False elif isinstance(node, ast.ExceptHandler): if isinstance(node.name, ast.Name): return node.name.id == name elif isinstance(node.name, str): return node.name == name elif isinstance(node, ast.Expr): if isinstance(node.value, (ast.DictComp, ast.GeneratorExp, ast.ListComp, ast.SetComp)): return node_defines_name(node.value, name) elif isinstance(node, ast.For): return isinstance(node.target, ast.Name) and node.target.id == name elif isinstance(node, ast.FunctionDef): return node.name == name elif isinstance(node, (ast.Import, ast.ImportFrom)): return next((alias for alias in node.names if (alias.asname or alias.name) == name), None) is not None return False
def infer(node, context, solver, from_call=False): """Infer the type of a given AST node""" if isinstance(node, ast.Num): return infer_numeric(node, solver) elif isinstance(node, ast.Str): return solver.z3_types.string elif (sys.version_info[0] >= 3 and sys.version_info[1] >= 6 and (isinstance(node, ast.FormattedValue) or isinstance(node, ast.JoinedStr))): # Formatted strings were introduced in Python 3.6 return solver.z3_types.string elif isinstance(node, ast.Bytes): return solver.z3_types.bytes elif isinstance(node, ast.List): return infer_list(node, context, solver) elif isinstance(node, ast.Dict): return infer_dict(node, context, solver) elif isinstance(node, ast.Tuple): return infer_tuple(node, context, solver) elif isinstance(node, ast.NameConstant): return infer_name_constant(node, solver) elif isinstance(node, ast.Set): return infer_set(node, context, solver) elif isinstance(node, ast.BinOp): return infer_binary_operation(node, context, solver) elif isinstance(node, ast.BoolOp): return infer_boolean_operation(node, context, solver) elif isinstance(node, ast.UnaryOp): return infer_unary_operation(node, context, solver) elif isinstance(node, ast.IfExp): return infer_if_expression(node, context, solver) elif isinstance(node, ast.Subscript): return infer_subscript(node, context, solver) elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.Await): # Await and Async were introduced in Python 3.5 return infer(node.value, context, solver) elif isinstance(node, ast.Yield): return infer(node.value, context, solver) elif isinstance(node, ast.Compare): return infer_compare(node, context, solver) elif isinstance(node, ast.Name): return infer_name(node, context) elif isinstance(node, ast.ListComp): return infer_sequence_comprehension(node, solver.z3_types.list, context, solver) elif isinstance(node, ast.SetComp): return infer_sequence_comprehension(node, solver.z3_types.set, context, solver) elif isinstance(node, ast.DictComp): return infer_dict_comprehension(node, context, solver) elif isinstance(node, ast.Call): return infer_func_call(node, context, solver) elif isinstance(node, ast.Attribute): return infer_attribute(node, context, from_call, solver) elif isinstance(node, ast.Lambda): return _infer_lambda(node, context, solver) raise NotImplementedError("Inference for expression {} is not implemented yet.".format(type(node).__name__))
def peval_comprehension(state, node, ctx): accum_cls = { ast.ListComp: ListAccumulator, ast.GeneratorExp: GeneratorExpAccumulator, ast.SetComp: SetAccumulator, ast.DictComp: DictAccumulator, } # variables from generators temporary mask bindings target_names = set() for generator in node.generators: if type(generator.target) == ast.Name: target_names.add(generator.target.id) else: target_names.update([elt.id for elt in generator.target.elts]) # pre-evaluate the expression elt_bindings = dict(ctx.bindings) for name in target_names: if name in elt_bindings: del elt_bindings[name] elt_ctx = ctx.update(bindings=elt_bindings) if type(node) == ast.DictComp: elt = ast.Tuple(elts=[node.key, node.value]) else: elt = node.elt state, new_elt = _peval_expression(state, elt, elt_ctx) try: state, container = _peval_comprehension( state, accum_cls[type(node)], new_elt, node.generators, ctx) evaluated = True except CannotEvaluateComprehension: evaluated = False if evaluated: return state, KnownValue(value=container) else: state, new_elt = map_reify(state, new_elt) state, new_generators = _peval_comprehension_generators(state, node.generators, ctx) if type(node) == ast.DictComp: key, value = new_elt.elts return state, replace_fields(node, key=key, value=value, generators=new_generators) else: return state, replace_fields(node, elt=new_elt, generators=new_generators)