So I have this really long if else block and I was wondering if there is a way to simplify it?
def position(self, k):
if self.b == None:
self.b = k
if (self.b).location_of(k) == 0:
if self.aquire(0) == None:
self.put(0, ABK(k))
else:
self.aquire(0).insert(k)
elif (self.b).location_of(k) == 1:
if self.aquire(1) == None:
self.put(1, ABK(k))
else:
self.aquire(1).insert(k)
elif (self.b).location_of(k) == 2:
if self.aquire(2) == None:
self.put(2, ABK(k))
else:
self.aquire(2).insert(k)
You could store the value of self.b.location_of(k) on a variable and use it later to call your functions.
def position(self, k):
if self.b is None:
self.b = k
loc = self.b.location_of(k)
if loc < 0 or loc > 2:
return # Return in case the value is out of scope
if self.aquire(loc) is None:
self.put(loc, ABK(k))
else:
self.aquire(loc).insert(k)
Edit:
Olvin Roght pointed out that you can also save the result of the self.aquire(loc) call:
def position(self, k):
if self.b is None:
self.b = k
loc = self.b.location_of(k)
if loc < 0 or loc > 2:
return
aqu = self.aquire(loc)
if aqu is None:
self.put(loc, ABK(k))
else:
aqu.insert(k)
As of python 3.8, you can achieve a result similar to the other answers in a shorter manner using the walrus operator (:=), more formally known as the assignment expression operator. This sort of inline assignment is similar to the way assignment can sometimes be done in nested ifs in C:
def position(self, k):
if self.b is None:
self.b = k
if 0 <= (loc := self.b.location_of(k)) <= 2:
if (val := self.aquire(loc)) is None:
self.put(loc, ABK(k))
else:
val.insert(k)
In addition to the more obvious changes, I recommend using x is None rather than x == None, as it is the more idiomatic comparison.
Related
I was trying to solve a codewars problem here, and I got a bit stuck. I believe I should be using nested currying in Python.
Let us just take the case of add. Let us constrain the problem even more, and just get nested add working on the right hand side, i.e. write an add function such that
print((add)(3)(add)(5)(4))
prints 12.
It should be possible to nest it as deep as required, for e.g. I want
print((add)(add)(3)(4)(add)(5)(6))
should give me 18.
What I have done so far -
My initial attempt is to use the following nested function -
def add_helper():
current_sum = 0
def inner(inp):
if isinstance(inp, int):
nonlocal current_sum
current_sum += inp
print(f"current_sum = {current_sum}")
return inner
return inner
add = add_helper()
However, this does not do the trick. Instead, I get the following output, for when I do something like print((add)(add)(3)(4)(add)(5)(6))
current_sum = 3
current_sum = 7
current_sum = 12
current_sum = 18
<function add_helper.<locals>.inner at 0x...>
Does anyone know how I have to change my function so that I just return 18, because the function will know it is "done"?
Any help will be appreciated!
UPDATE
After looking at Bharel's comments, I have the following so far -
def add_helper():
val = 0
ops_so_far = []
def inner(inp):
if isinstance(inp, int):
nonlocal val
val += inp
return inner
else:
ops_so_far.append(("+", val))
inp.set_ops_so_far(ops_so_far)
return inp
def set_ops_so_far(inp_list):
nonlocal ops_so_far
ops_so_far = inp_list
def get_val():
nonlocal val
return val
def get_ops_so_far():
nonlocal ops_so_far
return ops_so_far
inner.get_ops_so_far = get_ops_so_far
inner.set_ops_so_far = set_ops_so_far
inner.get_val = get_val
return inner
def mul_helper():
val = 1
ops_so_far = []
def inner(inp):
if isinstance(inp, int):
nonlocal val
val *= inp
return inner
else:
ops_so_far.append(("*", val))
inp.set_ops_so_far(ops_so_far)
return inp
def get_ops_so_far():
nonlocal ops_so_far
return ops_so_far
def set_ops_so_far(inp_list):
nonlocal ops_so_far
ops_so_far = inp_list
def get_val():
nonlocal val
return val
inner.get_ops_so_far = get_ops_so_far
inner.get_val = get_val
inner.set_ops_so_far = set_ops_so_far
return inner
add = add_helper()
mul = mul_helper()
and now when I do
res = (add)(add)(3)(4)(mul)(5)(6)
print(res.get_ops_so_far())
print(res.get_val())
I get
[('+', 0), ('+', 7)]
30
Still not sure if this is the correct direction to be following?
This is how I solved it for anyone still looking in the future -
from copy import deepcopy
def start(arg):
def start_evalutaion(_arg, eval_stack, variables):
new_eval_stack = deepcopy(eval_stack)
new_variables = deepcopy(variables)
to_ret = evaluate_stack(_arg, new_eval_stack, new_variables)
if to_ret is not None:
return to_ret
def inner(inner_arg):
return start_evalutaion(
inner_arg, new_eval_stack, new_variables
)
return inner
return start_evalutaion(arg, [], dict())
add = lambda a, b, variables: variables.get(a, a) + variables.get(b, b)
sub = lambda a, b, variables: variables.get(a, a) - variables.get(b, b)
mul = lambda a, b, variables: variables.get(a, a) * variables.get(b, b)
div = lambda a, b, variables: variables.get(a, a) // variables.get(b, b)
def let(name, val, variables):
variables[name] = val
return
def return_(val, variables):
return variables.get(val, val)
def evaluate_stack(_arg, eval_stack, variables):
if callable(_arg):
if _arg.__name__ == "return_":
req_args = 1
else:
req_args = 2
eval_stack.append((_arg, req_args, []))
else:
while True:
func_to_eval, req_args, args_so_far = eval_stack[-1]
args_so_far.append(_arg)
if len(args_so_far) == req_args:
eval_stack.pop()
_arg = func_to_eval(*args_so_far, variables)
if func_to_eval.__name__ == "return_":
return _arg
elif _arg is None:
break
else:
break
Passes all testcases
I have a class and some functions. In the 'check_reflexive()' function, there is a variable called reflexive_list. I want to use this variable also in the 'antisymmetric' function.
I checked some examples about class but didn't find a specific example to solve this problem.
I'll be waiting for your advice. Hope you have a nice day
class MyClass():
def __init__(self):
def checkif_pair(k):
for a in k:
if a%2 == 0:
None
else:
return False
return True
def check_reflexive(k):
j = 0
z = 0
reflexive_list = []
while j < len(k):
i = 0
while i < len(k):
if k[i] == k[j]:
tup = k[j],k[i]
reflexive_list.append(tup)
i += 1
else:
None
j = j + 1
else:
None
print(reflexive_list)
if len(reflexive_list) == len(self.list1):
return True
else:
return False
def antisymmetric(k):
antisymettric_list = []
for b in k:
swap1 = b[0]
swap2 = b[1]
newtuple = (swap2, swap1)
antisymettric_list.append(newtuple)
for ü in reflexive_list:
if ü in antisymettric_list:
antisymettric_list.remove(ü)
else:
None
print(antisymettric_list)
for q in antisymettric_list:
if q in k:
print("The system is not Anti-Symmetric.")
break
print("The system is Anti-Symmetric.")
def transitive(k):
result = {}
for first, second in k:
result.setdefault(first, []).append(second)
print(result)
for a, b in k:
for x in result[b]:
if x in result[a]:
None
else:
print("There is no {} in the {}".format(x, result[a]))
return False
return True
You can just use reflexive_list as an instance variable. Just add a constructor where the variable is defined:
class MyClass():
def __init__(self):
self.reflexive_list = []
And everytime you want to use it inside the function, you use self.reflexive_list
The Question
Is there a straightforward algorithm for figuring out if a variable is "used" within a given scope?
In a Python AST, I want to remove all assignments to variables that are not otherwise used anywhere, within a given scope.
Details
Motivating example
In the following code, it is obvious to me (a human), that _hy_anon_var_1 is unused, and therefore the _hy_anon_var_1 = None statements can be removed without changing the result:
# Before
def hailstone_sequence(n: int) -> Iterable[int]:
while n != 1:
if 0 == n % 2:
n //= 2
_hy_anon_var_1 = None
else:
n = 3 * n + 1
_hy_anon_var_1 = None
yield n
# After
def hailstone_sequence(n: int) -> Iterable[int]:
while n != 1:
if 0 == n % 2:
n //= 2
else:
n = 3 * n + 1
yield n
Bonus version
Extend this to []-lookups with string literals as keys.
In this example, I would expect _hyx_letXUffffX25['x'] to be eliminated as unused, because _hyx_letXUffffX25 is local to h, so _hyx_letXUffffX25['x'] is essentially the same thing as a local variable. I would then expect _hyx_letXUffffX25 itself to be eliminated once there are no more references to it.
# Before
def h():
_hyx_letXUffffX25 = {}
_hyx_letXUffffX25['x'] = 5
return 3
# After
def h():
return 3
From what I can tell, this is somewhat of an edge case, and I think the basic algorithmic problem is the same.
Definition of "used"
Assume that no dynamic name lookups are used in the code.
A name is used if any of these are true in a given scope:
It is referenced anywhere in an expression. Examples include: an expression in a return statement, an expression on the right-hand side of an assignment statement, a default argument in a function definition, being referenced inside a local function definition, etc.
It is referenced on the left-hand side of an "augmented assignment" statement, i.e. it is an augtarget therein. This might represent "useless work" in a lot of programs, but for the purpose of this task that's OK and distinct from being an entirely unused name.
It is nonlocal or global. These might be useless nonlocals or globals, but because they reach beyond the given scope, it is OK for my purposes to assume that they are "used".
Please let me know in the comments if this seems incorrect, or if you think I am missing something.
Examples of "used" and "unused"
Example 1: unused
Variable i in f is unused:
def f():
i = 0
return 5
Example 2: unused
Variable x in f is unused:
def f():
def g(x):
return x/5
x = 10
return g(100)
The name x does appear in g, but the variable x in g is local to g. It shadows the variable x created in f, but the two x names are not the same variable.
Variation
If g has no parameter x, then x is in fact used:
def f():
x = 10
def g():
return x/5
return g(100)
Example 3: used
Variable i in f is used:
def f():
i = 0
return i
Example 4: used
Variable accum in silly_map and silly_sum is used in both examples:
def silly_map(func, data):
data = iter(data)
accum = []
def _impl():
try:
value = next(data)
except StopIteration:
return accum
else:
accum.append(value)
return _impl()
return _impl()
def silly_any(func, data):
data = iter(data)
accum = False
def _impl():
nonlocal accum, data
try:
value = next(data)
except StopIteration:
return accum
else:
if value:
data = []
accum = True
else:
return _impl()
return _impl()
The solution below works in two parts. First, the syntax tree of the source is traversed and all unused target assignment statements are discovered. Second, the tree is traversed again via a custom ast.NodeTransformer class, which removes these offending assignment statements. The process is repeated until all unused assignment statements are removed. Once this is finished, the final source is written out.
The ast traverser class:
import ast, itertools, collections as cl
class AssgnCheck:
def __init__(self, scopes = None):
self.scopes = scopes or cl.defaultdict(list)
#classmethod
def eq_ast(cls, a1, a2):
#check that two `ast`s are the same
if type(a1) != type(a2):
return False
if isinstance(a1, list):
return all(cls.eq_ast(*i) for i in itertools.zip_longest(a1, a2))
if not isinstance(a1, ast.AST):
return a1 == a2
return all(cls.eq_ast(getattr(a1, i, None), getattr(a2, i, None))
for i in set(a1._fields)|set(a2._fields) if i != 'ctx')
def check_exist(self, t_ast, s_path):
#traverse the scope stack and remove scope assignments that are discovered in the `ast`
s_scopes = []
for _ast in t_ast:
for sid in s_path[::-1]:
s_scopes.extend(found:=[b for _, b in self.scopes[sid] if AssgnCheck.eq_ast(_ast, b) and \
all(not AssgnCheck.eq_ast(j, b) for j in s_scopes)])
self.scopes[sid] = [(a, b) for a, b in self.scopes[sid] if b not in found]
def traverse(self, _ast, s_path = [1]):
#walk the ast object itself
_t_ast = None
if isinstance(_ast, ast.Assign): #if assignment statement, add ast object to current scope
self.traverse(_ast.targets[0], s_path)
self.scopes[s_path[-1]].append((True, _ast.targets[0]))
_ast = _ast.value
if isinstance(_ast, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
s_path = [*s_path, (nid:=(1 if not self.scopes else max(self.scopes)+1))]
if isinstance(_ast, (ast.FunctionDef, ast.AsyncFunctionDef)):
self.scopes[nid].extend([(False, ast.Name(i.arg)) for i in _ast.args.args])
_t_ast = [*_ast.args.defaults, *_ast.body]
self.check_exist(_t_ast if _t_ast is not None else [_ast], s_path) #determine if any assignment statement targets have previously defined names
if _t_ast is None:
for _b in _ast._fields:
if isinstance((b:=getattr(_ast, _b)), list):
for i in b:
self.traverse(i, s_path)
elif isinstance(b, ast.AST):
self.traverse(b, s_path)
else:
for _ast in _t_ast:
self.traverse(_ast, s_path)
Putting it all together:
class Visit(ast.NodeTransformer):
def __init__(self, asgn):
super().__init__()
self.asgn = asgn
def visit_Assign(self, node):
#remove assignment nodes marked as unused
if any(node.targets[0] == i for i in self.asgn):
return None
return node
def remove_assgn(f_name):
tree = ast.parse(open(f_name).read())
while True:
r = AssgnCheck()
r.traverse(tree)
if not (k:=[j for b in r.scopes.values() for k, j in b if k]):
break
v = Visit(k)
tree = v.visit(tree)
return ast.unparse(tree)
print(remove_assgn('test_name_assign.py'))
Output Samples
Contents of test_name_assign.py:
def hailstone_sequence(n: int) -> Iterable[int]:
while n != 1:
if 0 == n % 2:
n //= 2
_hy_anon_var_1 = None
else:
n = 3 * n + 1
_hy_anon_var_1 = None
yield n
Output:
def hailstone_sequence(n: int) -> Iterable[int]:
while n != 1:
if 0 == n % 2:
n //= 2
else:
n = 3 * n + 1
yield n
Contents of test_name_assign.py:
def h():
_hyx_letXUffffX25 = {}
_hyx_letXUffffX25['x'] = 5
return 3
Output:
def h():
return 3
Contents of test_name_assign.py:
def f():
i = 0
return 5
Output:
def f():
return 5
Contents of test_name_assign.py:
def f():
x = 10
def g():
return x/5
return g(100)
Ouptut:
def f():
x = 10
def g():
return x / 5
return g(100)
This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
I'm working with binary tree in python. I need to create a method which searches the tree and return the best node where a new value can be inserted. But i'm have trouble returning a value from this recursive function. I'm a total newbie in python.
def return_key(self, val, node):
if(val < node.v):
if(node.l != None):
self.return_key(val, node.l)
else:
print node.v
return node
else:
if(node.r != None):
#print node.v
self.return_key(val, node.r)
else:
print node.v
return node
Printing node.v prints the node value, but when i print the returned node :
print ((tree.return_key(6, tree.getRoot().v)))
it prints
None
as result.
You need to return the result of your recursive call. You are ignoring it here:
if(node.l != None):
self.return_key(val, node.l)
and
if(node.r != None):
self.return_key(val, node.r)
Recursive calls are no different from other function calls, you still need to handle the return value if there is one. Use a return statement:
if(node.l != None):
return self.return_key(val, node.l)
# ...
if(node.r != None):
return self.return_key(val, node.r)
Note that since None is a singleton value, you can and should use is not None here to test for the absence:
if node.l is not None:
return self.return_key(val, node.l)
# ...
if node.r is not None:
return self.return_key(val, node.r)
I suspect you are passing in the wrong arguments to the call to begin with however; if the second argument is to be a node, don't pass in the node value:
print(tree.return_key(6, tree.getRoot())) # drop the .v
Also, if all your node classes have the same method, you could recurse to that rather than using self.return_value(); on the Tree just do:
print tree.return_key(6)
where Tree.return_key() delegates to the root node:
def return_key(self, val):
root = tree.getRoot()
if root is not None:
return tree.getRoot().return_key(val)
and Node.return_key() becomes:
def return_key(self, val):
if val < self.v:
if self.l is not None:
return self.l.return_key(val)
elif val > self.v:
if self.r is not None:
return self.r.return_key(val)
# val == self.v or child node is None
return self
I updated the val testing logic here too; if val < self.v (or val < node.v in your code) is false, don't assume that val > self.v is true; val could be equal instead.
Here's a minimalistic view of my problem (removing all unnecessary details). Essentially, it is an "assembly code" executor:
while(self.pc < len(self.memory)):
instruction = [int(i) for i in str(self.memory[self.pc])]
#simulated "switch" statement.
def switch(Opcode):
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
def add():
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
self.clock += self.clockSpeed['add']
def subtract():
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
self.clock += self.clockSpeed['subtract']
def invalid():
raise ValueError('invalid Opcode in instruction: {}'.format(instruction)
return {
0: add,
1: subtract,
"invalid": invalid
}.get(Opcode, "invalid")()
switch(instruction[0])
self.pc += 1
when I run this program with a simple array of around 40 elements (slightly more complicated method, but not much more) using the timeit module, it does take quite some time:
print 'timing execution of execute: ', timeit.timeit('vm.CPUexecuteProgram()', setup="from __main__ import OS; vm=OS(); vm.AbsoluteLoader('../assembly_code/assemble_code.exe')")
timing execution of execute: 0.673621892929
I believe that the definition is "re-making" itself on every iteration. Would there be a more efficient way which would follow the same "pattern" shown here? I'd like to avoid using if/elif/else if possible, to make it more readable.
This:
if op1['mode'] = self.modes['gpr']:
Needs to be:
if op1['mode'] == self.modes['gpr']:
For all of your comparisons. The double-equal is "does left equal right?". The single equal is "assign right to left, then return right".
Yes, you code creates all the functions and the entire dictionary on every instruction. In your real code (assuming 40 distinct opcodes), this means at least 42 object instantiations (1 per opcode, switch, the dict) per instruction executed. You can simply pull the loop-invariant parts (creation of add, sub, ...; creation of the opcode->function dict) out of the loop, make op1 and op2 parameters, and reduce the loop to this:
while self.pc < len(self.memory):
instruction = ...
op1 = ...
op2 = ...
implementations[instruction](op1, op2)
self.pc += 1
That should shave off a considerable fraction of the time. There are probably other places where one can optimize a bit, but since that isn't your real code and it's quite sloppy (several syntax errors, some parts look wrong) I will refrain from guessing.
Rearrange it:
def add(op1, op2):
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] + op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] + op2['opValue']
self.clock += self.clockSpeed['add']
def subtract(op1, op2):
if op1['mode'] = self.modes['gpr']:
self.gpr[op1['gpr']] = op1['opValue'] - op2['opValue']
else:
self.memory[op1['opAddress']] = op1['opValue'] - op2['opValue']
self.clock += self.clockSpeed['subtract']
def invalid(op1, op2):
raise ValueError('invalid Opcode in instruction: {}'.format(instruction)
switch = {0: add, 1: subtract}
while (self.pc < len(self.memory)):
instruction = [int(i) for i in str(self.memory[self.pc])]
Opcode = instruction[0]
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
switch.get(Opcode, invalid)(op1, op2)
self.pc += 1
this way it won't redefine all the methods every time.
import operator
class Something(object):
_operations = {
0: lambda self, instruction: self._execute("add", instruction),
1: lambda self, instruction: self._execute("subtract", instruction),
"invalid": lambda self, instruction: self_invalid(instruction)
}
_operators = {
"add": operator.add,
"substract": operator.sub
}
def _execute(self, operation, instruction):
op1 = getOperand(instruction[1], instruction[2])
op2 = getOperand(instruction[3], instruction[4])
operator = self._operators[operation]
val = operator(op1, op2)
if op1['mode'] == self.modes['gpr']:
self.gpr[op1['gpr']] = val
else:
self.memory[op1['opAddress']] = val
self.clock += self.clockSpeed[operation]
def _invalid(self, instruction):
raise ValueError(
'invalid Opcode in instruction: {}'.format(instruction)
)
def _switch(self, instruction):
return self._operations.get(instruction[0], self._invalid)(self, instruction)
def whatever(self):
while self.pc < len(self.memory):
instruction = [int(i) for i in str(self.memory[self.pc])]
self._switch(instruction)
self.pc += 1