I have a function as follows:
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
global qstatnum
qstatnum = {}
qstatnum[gatnum] = []
qstatnum[gatnum].append(qstat) #seems to be a problem
return qstat
However, there is a problem. Let's say I run it once. There will be one item in the list. Then, I run it a second time, with an item distinguishable from the second supposed to be added to the list. When I print qstatnum[gatnum], the list contains only the second item, leading me to believe that the .append() statement is somehow incorrectly written and overwriting any previous additions to the list.
Is this a correct diagnosis? Why would this be? Any help would be appreciated. Thanks!
Each time you call the function, you are creating a new qstatnum dict, so the solution is to create the dictionary outside the function:
qstatnum = {}
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
try:
qstatnum[qstat].append(gatnum)
except:
qstatnum[qstat] = [gatnum]
return qstat
You need a try: except: block to verify if the key already exists in the dictionary, if it doesn't exists, just add the first value, else use append.
#DanD. approach seems to be shorter, please take a look:
qstatnum = {}
def control(qstat):
gatnum = int(input("What number of control gates is this control qubit a part of?"))
qstatnum.setdefault(qstat, []).append(gatnum)
return qstat
Every time the method is called, qstatnum is set to empty. So basically you are appending to nothing every time.
Related
I am working on a program that can be used to add a given value say a car dealership with the cars it owns:
for example
car_storage = []
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
else:
items.append([dealership, car])
return
add_cars("Manchester", "Mini")
add_cars("London", "Toyota")
add_cars("London", "BMW")
add_cars("London", "BMW")
#Desired output
[["Nottingham", "Audi"],["Manchester","Mini"],["London", "Lorry", "BMW", "BMW"]]
However, my code never adds to the list, where am I going wrong?
The issue with your code as #juanpa.arrivillaga said is that the before you add the first item the list car_dealership is empty so nothing in your function executes.
Your approach however is almost correct, Python supports else keyword with for loops. What it means is, if the for loop ran without breaking (no break statements) the else statement is called. For example
for i in range(1, 4):
if i==2:
break
else: # Not executed as there is a break
# if we remove the break the else will run
print("No Break")
Now similarly in your code. you can use the same concept.
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
else:
car_storage.append([dealership, car])
Which is very similar to your original code except the indentation level on the else part.
Now in this case since you're returning and not breaking you can even get away with removing the else entirely since the function will never reach there
def add_cars(dealership, car):
for items in car_storage:
for values in items:
if dealership in items:
#Adds car whether it exists or not in list
items.append(car)
return
#If the dealership does not exist it is created and added to the list
car_storage.append([dealership, car])
I often have the case where I use two variables, one of them being the "current" value of something, another one a "newly retrieved" one.
After checking for equality (and a relevant action taken), they are swapped. This is then repeated in a loop.
import time
import random
def get_new():
# the new value is retrieved here, form a service or whatever
vals = [x for x in range(3)]
return random.choice(vals)
current = None
while True:
# get a new value
new = get_new()
if new != current:
print('a change!')
else:
print('no change :(')
current = new
time.sleep(1)
This solution works but I feel that it is a naïve approach and I think I remember (for "write pythonic code" series of talks) that there are better ways.
What is the pythonic way to handle such mechanism?
Really, all you have is a simple iteration over a sequence, and you want to detect changes from one item to the next. First, define an iterator that provides values from get_new:
# Each element is a return value of get_new(), until it returns None.
# You can choose a different sentinel value as necessary.
sequence = iter(get_new, None)
Then, get two copies of the iterator, one to use as a source for current values, the other for new values.
i1, i2 = itertools.tee(sequence)
Throw out the first value from one of the iterators:
next(i2)
Finally, iterate over the two zipped together. Putting it all together:
current_source, new_source = tee(iter(get_new, None))
next(new_source)
for current, new in zip(current_source, new_source):
if new != current:
...
else:
...
time.sleep(1)
Using itertoolz.cons:
current_source, new_source = tee(iter(get_new, None))
for current, new in zip(cons(None, current_source), new_source)):
...
def make(node): # takes some input
for reg_names in reg.names # dont worry about reg_names and reg.names
if reg.size > 0: #reg.size is an inbuilt function
found_dict = {} # first dictionary
found_dict['reg.name'] = 'reg.size' # i want to save the name of the register : size of the register in the format name : size
else:
not_found_dict = {}
not_found_dict['reg.name'] = 'reg.size' #again, i want to save the name of the register : size of the register in the format name : size
return found_dict, not_found_dict
Ok, so can you tell me whether from the for loop above, if the constructs for creating the dictionaries (found_dict and not_found_dict) are correct assuming reg.name and reg.size are valid constructs?
I then want to use found_dict in function_one and not_found_dict in function_two like below:
def function_one(input): # should this input be the function 'make' as I only want found_dict?
for name, size in found_dict.items(): #just for the names in found_dict
name_pulled = found_dict['reg.name'] # save the names temporarily to name_pulled using the key reg.name of found_dict
final_names[] = final_names.append(name_pulled) #save names from name_pulled into the list final_names and append them through the for loop. will this work?
def function_two(input): # i need not_found_dict so what should this input be?
for name, size in not_found_dict.items(): #using the names in not_found_dict
discard_name_pulled = not_found_dict['reg.name'] # save the names temporarily to discard_name_pulled using on the 'reg.name' from not_found_dict which is essentially the key to the dict
not_used_names[] = not_used_names.append(discard_name_pulled) # in the same way in function_one, save the names to the list not_used_names and append them through the for loop. Will this construct work?
Main question is, since def make is returning two dictionaries (found_dict and not_found_dict) how do I correctly input found_dict in function_one and not_found_dict in function_two?
First of all in your first section in the for loop every time you do :found_dict = {} or not_found_dict = {} you are clearing the contents of the dictionary. I'm not sure if this is what you want.
Second if you want to return more than one thing from a function you could always return them as an array or a tuple, something like this:
return [found_dict, not_found_dict]
Look at this question for more information.
After you return your array or tuple you can then store it in another variable like this:
result=make(inputVariable)
this will let you use each element as you want.
result[0]
result[1]
you can input them into the functions you want like this:
def function_one(inputParameter, found_dict):
#code ....
def function_one(inputParameter, not_found_dict):
#code ....
function_one(inputVariable, result[0])
function_two(inputVariable, result[1])
This is what I have so far:
def lists():
global ClientList, highList, moderateList
ClientList = [ ["NeQua,High"],
["ImKol,Moderate"],
["YoTri,Moderate"],
["RoDen,High"],
["NaThe,Moderate"],
["ReWes,Moderate"],
["BrFre,High"],
["KaDat,High"],
["ViRil,High"],
["TrGeo,High"]]
highList = ["Running", "Swimming", "Aerobics", "Football", "Tennis"]
moderateList = ["Walking", "Hicking", "Cleaning", "Skateboarding", "Basketball"]
checkclient()
def checkclient():
global ClientList, highList, moderateList
answer = input("please enter the client ID: ")
answer2 = next(answer for answer in ClientList)
print(answer)
So I want to input the specific clientID, I want python to then find the client ID in the list, print the clientID with the intensity level (high or moderate) so I can use it later to ask the user how many minutes they spent exercising in the different activities based on whether their intensity was high or moderate.
At the moment the code only prints the first part of the list regardless of what the variable answer is: ["NeQua, High"].
Please can you tell me how to fix this and try to keep it simple as I am relatively new to Python.
Thanks
Cameron
Use a dictionary instead (and there's no need to wrap it in a function that does nothing but create global objects).
ClientList = {"NeQua":"High",
"ImKol":"Moderate",
"YoTri":"Moderate",
"RoDen":"High",
"NaThe":"Moderate",
"ReWes":"Moderate",
"BrFre":"High",
"KaDat":"High",
"ViRil":"High",
"TrGeo":"High"}
You don't need to specify mutable objects like lists or dictionaries as global if all you want to do is mutate them. You only need global if you want local assignments to the same name to also assign to the global name. More importantly, though, next() just returns the next element in an iterable. As a list is an ordered sequence, a generator that you make out of it with answer for answer in ClientList will have the same order, and the next() of that (redundant, I might add) generator will always be the first element of ClientList, because you keep making a new generator. If you want next() to proceed through the whole thing, you'd have to save it first. However, none of that is necessary here. Just access the dictionary. I use get() here to avoid errors if the user tries to access a user that doesn't exist.
def checkclient():
answer = input("please enter the client ID: ")
print(ClientList.get(answer, 'Not found.'))
checkclient()
Also note that a function must be defined before it is called (order matters).
You might change it as follows:
def checkclient():
global ClientList, highList, moderateList
answer = input("please enter the client ID: ") # input: NaThe
try:
answer2 = next(a for a in ClientList if answer in a)
except StopIteration:
checkclient()
else:
print(answer2) # NaThe,Moderate
next returns the first element of an iterable so you always get the first element of ClientList, so you need to filter out the ones containing your ID.
In web2py I have been trying to break down this list comprehension so I can do what I like with the categories it creates. Any ideas as to what this breaks down to?
def menu_rec(items):
return [(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)) for x in items or []]
In addition the following is what uses it:
response.menu = [(SPAN('Catalog', _class='highlighted'), False, '',
menu_rec(db(db.category).select().as_trees()) )]
So far I've come up with:
def menu_rec(items):
for x in items:
return x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children))
I've got other variations of this but, every variation only gives me back 1(one) category, when compared to the original that gives me all the categories.
Can anyone see where I'm messing this up at? Any and all help is appreciated, thank you.
A list comprehension builds a list by appending:
def menu_rec(items):
result = []
for x in items or []:
url = URL('shop', 'category', args=pretty_url(x.id, x.slug))
menu = menu_rec(x.children) # recursive call
result.append((x.title, None, url, menu))
return result
I've added two local variables to break up the long line somewhat, and to show how it recursively calls itself.
Your version returned directly out of the for loop, during the first iteration, and never built up a list.
You don't want to do return. Instead append to a list and then return the list:
def menu_rec(items):
result = []
for x in items:
result.append(x.title,None,URL('shop', 'category',args=pretty_url(x.id, x.slug)),menu_rec(x.children)))
return result
If you do return, it will return the value after only the first iteration. Instead, keep adding it to a list and then return that list at the end. This will ensure that your result list only gets returned when all the values have been added instead of just return one value.