better while loop structure in python - python

I have a function remove_it() that tries to remove some data and the removed data is added to the set removed. The main logic is that if there is more to remove, keep removing and my code looks like this:
removed = set()
prev_count = -1
while prev_count != len(removed):
prev_count = len(removed)
remove_it()
It bothers me a little that the while loop condition and the next line look very similar to each other. Is it normal or is there a better way to do it?
The logic in remove_it() is quite complicated: it detects some graph structure topology and after each round of removal the topology changes and I cannot know how it changes until the removal is done.
I was thinking of return bool value from remove_it() to track whether the set removed has changed. Then the while loop would be like
while remove_it():
pass
which is also strange to me. Is there a better way?

Your remove_it function has side effects and this makes program harder to read. You can rewrite it so that instead of modifying global removed variable it would return set of removed values. Then you can rewrite the loop:
removed = set()
while True:
removed_batch = remove_it()
if removed_batch:
removed += removed_batch
else:
break

Related

Python True Copy Within a Class

For some reason, I have a list that keeps getting modified despite being explicitly a deep copy. It appears to be unmodified as it goes through the loop, but it suddenly is modified once it exists? I must be missing something that pertains to Python's rules and logic, but I can't figure it out for the life of me.
def all_possible_states(self):
#creates many variations of a board from the available set of moves
to_return = [] #list of possible board states to return
#print(self.availible_moves)
list_to_copy = copy.deepcopy(self.availible_moves)
for item in self.availible_moves:
print('loop')
#append possible board state to list. set of availible moves for that board is one less. Done by removing item from that move list
to_return.append(board(self.player, copy.deepcopy(self.board.copy()), list_to_copy, self.plays, self.score, copy.deepcopy(item)))
#print(item)
print( self.avalible_moves) #shows the total set of moves. This is unmodified whenever it prints
print(list_to_copy)#deep copy of the original list. This is unmodified when it prints
print(to_return[len(to_return) - 1].availible_moves) #List of moves left availible for the board, this slowly shrinks for some reason each loop
print(self.availible_moves) #this is the original list, but it's not basically been cut all the way down for some reason
return to_return
Notice, the local variable list_to_copy is the deepcopy, not self.availible_moves. You are saving a deepcopy of self.availible_moves and it is being stored in the list_to_copy variable you defined. list_to_copy never changes as expected from a deepcopy. I'm not exactly sure what you are trying to do, but if you want, at the end you can reset self.availible_moves to be equal to list_to_copy and then it will be as if it never changed.
EDIT:
Actually, I think you have a spelling mistake, notice that you print(self.avalible_moves) and you are saying its not changing, when really what is changing is self.availible_moves. Notice the extra letter i in the first expression. This definitely is one of your problems.

How is the for-loop able to use a variable that isn't defined yet

I'm new to coding and I'm a little confused. How/why can a for loop use a variable that isn't defined yet?
For example:
demond = {'green':'grass', 'red':'fire', 'yellow':'sun'}
for i in demond:
print(i)
Output:
green
yellow
red
In python, you don't need to declare variables. In C/C++/JAVA etc. you will have to declare them first and then use them.
Variables are nothing but reserved memory locations to store values.Based on the data type of a variable, the interpreter allocates memory and decides what can be stored in the reserved memory.Python variables do not need explicit declaration to reserve memory space. The declaration happens automatically when you assign a value to a variable.
There are two things that you need to keep in mind:
because Python is a weakly-typed language, you do not need to explicitly declare any variable to a certain object type. This is something you already know, and why you can assign things without having to state what type they will be.
For loop constructs do a lot of things in the background that you don't explicitly see. This means that although it doesnt LOOK like anything is being defined, it is.
With that in mind, I dont want to really explain how for loops work, because there are already answers available for that but the main point is that a for loop in python is the same as the following pseudo code.
#set up your iterable
demond = SOME_ITERABLE_OBJECT (this can be a list, string, dict, etc)
#this
for i in demond:
do_something(i)
#is the same as this
i = demond[0] # the first item in demond
do_something(i)
i = demond[1] # the second item in demond
do_something(i)
i = demond[2]
...
...
..
i = demond[n] # the last item in demond
do_something(i)
Now your follow up question may be this: what makes it so that, in your code, for i in demond sets i to equal to it's keys? Well that is just part of the design of python, specifically how dicts work. What the for loop is ACTUALLY doing is calling an iterables next() function until the iterable generator is done. Each iterable can have a different result from a for loop (see the first link).
NOTE:
In my code example, I am setting i = demond[some_index]. This looks like a list index grab but it is really meant to just show that is iterating through the list in some sort of order. IT IS PSUEDO CODE. Just keep that in mind.

Python - disposable ifs

While writing state machines to analyze different types of text data, independent of language used (VBA to process .xls contents using arrays/dictionaries or PHP/Python to make SQL insert queries out of .csv's) I often ran into neccesity of something like
boolean = False
while %sample statement%:
x = 'many different things'
if boolean == False:
boolean = True
else:
%action that DOES depend on contents of x
that need to do every BUT first time I get to it%
Every time I have to use a construction like this, I can't help feeling noob. Dear algorithmic gurus, can you assure me that it's the only way out and there is nothing more elegant? Any way to specify that some statement should be "burnt after reading"? So that some stupid boolean is not going to be checked each iteration of the loop
The only things that come across as slightly "noob" about this style are:
Comparing a boolean variable to True or False. Just write if <var> or if not <var>. (I'll ignore the = vs == as a typo!)
Not giving the boolean variable a good name. I know that here boolean is just a placeholder name, but in general using a name like first_item_seen rather than something generic can make the code a lot more readable:
first_item_seen = False
while [...]:
[...]
if first_item_seen:
[...]
else:
first_item_seen = True
Another suggestion that can work in some circumstances is to base the decision on another variable that naturally conveys the same state. For instance, it's relatively common to have a variable that contains None for the first iteration, but contains a value for later iterations (e.g. the result so far); using this can make the code slightly more efficient and often slightly clearer.
If I understand your problem correctly, I'd try something like
x = 'many different things'
while %sample statements%:
x = 'many different things'
action_that_depends_on_x()
It is almost equivalent; the only difference is that in your version the loop body could be never executed (hence x never being computed, hence no side effects of computing x), in my version it is always computed at least once.

Pythonic way to add to a set and care about if it worked?

Often times I find that, when working with Pythonic sets, the Pythonic way seems to be absent.
For example, doing something like a dijkstra or a*:
openSet, closedSet = set(nodes), set(nodes)
while openSet:
walkSet, openSet = openSet, set()
for node in walkSet:
for dest in node.destinations():
if dest.weight() < constraint:
if dest not in closedSet:
closedSet.add(dest)
openSet.add(dest)
This is a weakly contrived example, the focus is the last three lines:
if not value in someSet:
someSet.add(value)
doAdditionalThings()
Given the Python way of working with, for example, accessing/using values of a dict, I would have expected to be able to do:
try:
someSet.add(value)
except KeyError:
continue # well, that's ok then.
doAdditionalThings()
As a C++ programmer, my skin crawls a bit that I can't even do:
if someSet.add(value):
# add wasn't blocked by the value already being present
doAdditionalThings()
Is there a more Pythonic (and if possible more efficient) way to work with this sort of set-as-guard usage?
The add operation is not supposed to also tell you if the item was already in the set; it just makes sure it is in there after you add it. Or put another way, what you want is not "add an item and check if it worked"; you want to first check if the item is there, and if not, then do some special stuff. If all you wanted to do was add the item, you wouldn't do the check at all. There is nothing unpythonic about this pattern:
if item not in someSet:
someSet.add(item)
doStuff()
else:
doOtherStuff()
It is true that the API could have been designed so that .add returned whether the item was already in there, but in my experience that's not a particularly common use case. Part of the point of sets is that you can freely add items without worrying about whether they were already in there (since adding an already-included item has no effect). Also, having .add return None is consistent with the general convention for Python builtin types that methods that mutate their arguments return None. It is really things like dict.setdefault (which gets an item but first adds it if isn't there) that are the unusual case.

conditionally setting and conditionally using a variable python

I know it is bad convention/design to conditionally declare a variable. i.e.:
if some_boolean:
x = 1
where x is not declared anywhere else. But is it bad to conditionally declare a variable if you only use it later on if that condition is met?
if some_boolean and some_other_boolean:
x+=1
It's dubious style, as it's prone to bugs based on imperfect, impartial understanding on some future maintainer's part. I also think that initially setting variables to None (unless more useful values are known for them) is helpful to readability, in part because it gives you one, natural place to document all of the variables with comments (rather than spreading such comments all over the place, which makes them hard to find;-).
if your code look like this
if some_boolean:
x = 1
# some actions
# not changing some_boolean
# but calculating some_other_boolean
# ...
if some_boolean and some_other_boolean:
x+=1
Can it be refactored to
def some_actions(some_args,...):
#...
def calculate_some_other_boolean(some_other_args,...):
#...
if some_boolean:
x = 1
some_actions(some_args,...)
if calculate_some_other_boolean(some_other_args,...):
x+=1
else:
some_actions(some_args,...)
?
From a very simple design perspective, I'd just default the boolean to false even if it maybe won't be used later. That way the boolean in question is not maybe defined or maybe actually a boolean value, and in the event that it is used, it has a proper value.
If you have two or three booleans set to false and they never get used, it's not going to make any significant difference in a big picture sense. If you have more than a few, though, it may indicate a design problem.

Categories