def visit_Compare(self, node):
"""
:type node: _ast.FunctionDef
"""
is_lambda_def = len(node.ops) == 1\
and type(node.ops[0]) is _ast.Gt \
and (type(node.left) is _ast.Tuple or type(node.left) is _ast.Name) \
and all(map(lambda t: type(t) == _ast.Name, getattr(node.left, 'elts', [])))
if not is_lambda_def:
return node
arguments = _transform_function_arguments(node.left)
function_body = node.comparators[0]
lambda_ast_transform = ast.Lambda(args=arguments,
body=function_body,
lineno=node.lineno,
col_offset=node.col_offset)
return lambda_ast_transform
python类FunctionDef()的实例源码
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
def CONTINUE(self, node):
# Walk the tree up until we see a loop (OK), a function or class
# definition (not OK), for 'continue', a finally block (not OK), or
# the top module scope (not OK)
n = node
while hasattr(n, 'parent'):
n, n_child = n.parent, n
if isinstance(n, LOOP_TYPES):
# Doesn't apply unless it's in the loop itself
if n_child not in n.orelse:
return
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
break
# Handle Try/TryFinally difference in Python < and >= 3.3
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
if n_child in n.finalbody:
self.report(messages.ContinueInFinally, node)
return
if isinstance(node, ast.Continue):
self.report(messages.ContinueOutsideLoop, node)
else: # ast.Break
self.report(messages.BreakOutsideLoop, node)
def __new__(cls, name, bases, dct):
slots = dct.get('__slots__', [])
orig_slots = []
for base in bases:
if hasattr(base, "__slots__"):
orig_slots += base.__slots__
if '__init__' in dct:
init = dct['__init__']
initproc = type.__new__(cls, name, bases, dct)
initproc_source = inspect.getsource(initproc)
ast = compile(initproc_source, "dont_care", 'exec', _ast.PyCF_ONLY_AST)
classdef = ast.body[0]
stmts = classdef.body
for declaration in stmts:
if isinstance(declaration, _ast.FunctionDef):
name1 = declaration.name
if name1 == '__init__': # delete this line if you do not initialize all instance variables in __init__
initbody = declaration.body
for statement in initbody:
if isinstance(statement, _ast.Assign):
for target in statement.targets:
name1 = target.attr
if name1 not in orig_slots:
slots.append(name1)
if slots:
dct['__slots__'] = slots
return type.__new__(cls, name, bases, dct)
def BUILD_CLASS(self, instr):
call_func = self.ast_stack.pop()
assert isinstance(call_func, _ast.Call)
func = call_func.func
assert isinstance(func, _ast.FunctionDef)
code = func.body
pop_assignment(code, '__module__')
doc = pop_doc(code)
ret = code.pop()
assert isinstance(ret, _ast.Return) and ret.value == 'LOAD_LOCALS'
bases = self.ast_stack.pop()
assert isinstance(bases, _ast.Tuple)
bases = bases.elts
name = self.ast_stack.pop()
class_ = _ast.ClassDef(name=name, bases=bases, body=code, decorator_list=[],
lineno=instr.lineno, col_offset=0)
self.ast_stack.append(class_)
def CALL_FUNCTION(self, instr):
nkwargs = instr.oparg >> 8
nargs = (~(nkwargs << 8)) & instr.oparg
args = []
keywords = []
for _ in range(nkwargs):
expr = self.ast_stack.pop()
name = self.ast_stack.pop()
keyword = _ast.keyword(arg=name.s, value=expr, lineno=instr.lineno)
keywords.insert(0, keyword)
for _ in range(nargs):
arg = self.ast_stack.pop()
args.insert(0, arg)
if len(args) == 1 and isinstance(args[0], (_ast.FunctionDef, _ast.ClassDef)):
function = args[0]
if function.decorator_list is None:
function.decorator_list = []
node = self.ast_stack.pop()
function.decorator_list.insert(0, node)
self.ast_stack.append(function)
return
node = self.ast_stack.pop()
callfunc = _ast.Call(func=node, args=args, keywords=keywords, starargs=None, kwargs=None,
lineno=instr.lineno, col_offset=0)
self.ast_stack.append(callfunc)
def __new__(cls, name: str, bases: list, dictionary: dict) -> object:
slots, original_slots = dictionary.get('__slots__', []), []
for base in bases:
if hasattr(base, "__slots__"):
original_slots += base.__slots__
if '__init__' in dictionary:
init_src = getsource(type.__new__(cls, name, bases, dictionary))
ast = compile(init_src, "", 'exec', _ast.PyCF_ONLY_AST, optimize=2)
for declaration in tuple(ast.body[0].body):
if isinstance(declaration, _ast.FunctionDef):
nombre = declaration.name
if nombre == '__init__':
initbody = declaration.body
for statement in initbody:
if isinstance(statement, _ast.Assign):
for target in statement.targets:
nombrecito = target.attr
if nombrecito not in original_slots:
slots.append(nombrecito)
dictionary['__slots__'] = namedtuple("AutoSlots", slots)(*slots)
dictionary['__doc__'] = dictionary.get(
'__doc__', f"""{name} class from '{dictionary['__module__']}'.
\nInstantiated using Angler AutoSlots MetaClass.
Mutable/writable/readable attributes: {dictionary['__slots__']}
\nThis does not make the {name} class Inmmutable.
\nAdding new attributes via assignments/setattr/etc is Blocked.
\nUses less memory, speeds up attribute accesses and avoid bugs
\nTry to add new attributes to this {name} class will raise:
AttributeError: {name} object has no attribute\n\n""" + __doc__
)
return type.__new__(cls, name, bases, dictionary)
def visit_FunctionDef(self, node):
"""
:type node: _ast.FunctionDef
"""
children = node.body
lambda_assign_children = [child for child in children
if type(child) == _ast.Assign
and len(child.targets) == 1
and type(child.value) == _ast.Compare
and (type(child.value.left) == _ast.Tuple or type(child.value.left) == _ast.Name)
and all(map(lambda t: type(t) == _ast.Name, getattr(child.value.left, 'elts', [])))]
# Support single line lambdas outside of assigns
other_children = [child for child in children if child not in lambda_assign_children]
for child in other_children:
CompareNodeVisitor().visit(child)
for assign_type_child in lambda_assign_children:
arguments = _transform_function_arguments(assign_type_child.value.left)
function_body = assign_type_child.value.comparators[0]
if _is_multiline_lambda(function_body):
all_statements = function_body.elts
return_statement = all_statements[-1]
statements = all_statements[0:len(all_statements) - 1]
statements = _transform_multiline_assignment_statements(statements)
return_statement = _transform_multiline_return_statement(return_statement)
assign_target = assign_type_child.targets[0]
if type(assign_target) is _ast.Attribute:
function_name = assign_target.attr
else:
function_name = assign_target.id
all_transformed_statements = statements + [return_statement]
functiondef_object = ast.FunctionDef(args = arguments,
body=all_transformed_statements,
lineno=assign_type_child.lineno,
name=function_name,
col_offset=assign_type_child.col_offset,
decorator_list=[])
children.insert(0, functiondef_object)
assign_type_child.value = ast.Name(id=functiondef_object.name,
col_offset=functiondef_object.col_offset,
lineno=functiondef_object.lineno,
ctx=ast.Load())
else:
lambda_ast_transform = ast.Lambda(args=arguments,
body=function_body,
lineno=assign_type_child.lineno,
col_offset = assign_type_child.col_offset)
assign_type_child.value = lambda_ast_transform
return node
def make_function(code, defaults=None, lineno=0):
from ..decompiler.disassemble import disassemble
instructions = Instructions(disassemble(code))
stmnts = instructions.stmnt()
if code.co_flags & 2:
vararg = None
kwarg = None
varnames = list(code.co_varnames[:code.co_argcount])
co_locals = list(code.co_varnames[code.co_argcount:])
#have var args
if code.co_flags & 4:
vararg = co_locals.pop(0)
#have kw args
if code.co_flags & 8:
kwarg = co_locals.pop()
args = [_ast.Name(id=argname, ctx=_ast.Param(), lineno=lineno, col_offset=0) for argname in varnames]
args = _ast.arguments(args=args,
defaults=defaults if defaults else [],
kwarg=kwarg,
vararg=vararg,
lineno=lineno, col_offset=0
)
if code.co_name == '<lambda>':
if len(stmnts) == 2:
if isinstance(stmnts[0], _ast.If) and isinstance(stmnts[1], _ast.Return):
assert len(stmnts[0].body) == 1
assert isinstance(stmnts[0].body[0], _ast.Return)
stmnts = [_ast.Return(_ast.IfExp(stmnts[0].test, stmnts[0].body[0].value, stmnts[1].value))]
assert len(stmnts) == 1, stmnts
assert isinstance(stmnts[0], _ast.Return)
stmnt = stmnts[0].value
ast_obj = _ast.Lambda(args=args, body=stmnt, lineno=lineno, col_offset=0)
else:
if instructions.seen_yield:
return_ = stmnts[-1]
assert isinstance(return_, _ast.Return)
assert isinstance(return_.value, _ast.Name)
assert return_.value.id == 'None'
return_.value = None
ast_obj = _ast.FunctionDef(name=code.co_name, args=args, body=stmnts, decorator_list=[], lineno=lineno, col_offset=0)
return ast_obj
def STORE_NAME(self, instr):
value = self.ast_stack.pop()
value = self.process_ifexpr(value)
if isinstance(value, _ast.Import):
if value.from_:
assert isinstance(self.ast_stack[-1], _ast.ImportFrom)
from_ = self.ast_stack.pop()
as_name = instr.arg
name = from_.names[0].name
if as_name != name:
from_.names[0].asname = as_name
self.ast_stack.append(from_)
else:
as_name = instr.arg
if value.names[0].asname is None:
base_name = value.names[0].name.split('.')[0]
if base_name != as_name:
value.names[0].asname = as_name
self.ast_stack.append(value)
elif isinstance(value, (_ast.Attribute)) and isinstance(value.value, (_ast.Import)):
asname = instr.arg
value = value.value
value.names[0].asname = asname
self.ast_stack.append(value)
elif isinstance(value, (_ast.ClassDef, _ast.FunctionDef)):
as_name = instr.arg
value.name = as_name
self.ast_stack.append(value)
elif isinstance(value, _ast.AugAssign):
self.ast_stack.append(value)
elif isinstance(value, _ast.Assign):
_ = self.ast_stack.pop()
assname = _ast.Name(instr.arg, _ast.Store(), lineno=instr.lineno, col_offset=0)
value.targets.append(assname)
self.ast_stack.append(value)
else:
assname = _ast.Name(instr.arg, _ast.Store(), lineno=instr.lineno, col_offset=0)
assign = _ast.Assign(targets=[assname], value=value, lineno=instr.lineno, col_offset=0)
self.ast_stack.append(assign)