Python3.4 Dictionary value replacement issue - python-3.x

I have some code which takes a list of dictionaries and creates another list of dictionaries.
Each dictionary in the list has two key/value pairs "ID" and "opcode", where "opcode" is a 32 bit number.
My code needs to create a second list of dictionaries where the opcodes are separated, i.e. a dictionary with opcode=5 would become two dictionaries with opcode=1 and opcode=4.
(opcode is a 32 bit number and my requirement is that only 1 bit is high, ie opcode=1,2,4,8,16 etc)
I've simplified the problem into the following; my code needs to turn this:
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
into this:
part_=[{"ID":1,"opcode":4},{"ID":2,"opcode":1},{"ID":2,"opcode":4},{"ID":3,"opcode":2},{"ID":3,"opcode":4}]
Currently my code is the following
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(i)
part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)
The output of the code is:
{'opcode': 4, 'ID': 1}
{'opcode': 1, 'ID': 2}
{'opcode': 2, 'ID': 3}
Interestingly if I modify the code slightly so that the value modification line is not there, the extra dictionaries are created, but obviously the opcode is not correct.
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part=[{"ID":1,"opcode":4},{"ID":2,"opcode":5},{"ID":3,"opcode":6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(i)
#part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)
The output is
{'ID': 1, 'opcode': 4}
{'ID': 2, 'opcode': 5}
{'ID': 2, 'opcode': 5}
{'ID': 3, 'opcode': 6}
{'ID': 3, 'opcode': 6}
I can get around the issue by going about the problem a different way, but in the interest in learning what is going on I'm out of my depth.

This is caused as when you append i to the new list you do not create a copy of the dictionary instead you add a reference to the original dictionary. This means that when you change the dictionary in the next line you also change value in part. This causes the loop not to match the any more parts of the opcode. You can see this if you print out the values of part at the end of your code.
The python documentation explains this as:
Assignment statements in Python do not copy objects, they create bindings between a target and an object. For collections that are mutable or contain mutable items, a copy is sometimes needed so one can change one copy without changing the other.
Reference
You can fix this by creating a copy of the dictionary when you append it. This will allow you change the value without affecting the original dictionary. Python allows you to copy objects using the copy module (Documentation).
Just import copy and then do part_.append(copy.copy(i)) instead of part_.append(i).
import copy
def bit_set(theNumber,bit):
return theNumber&(1<<bit)!=0
part = [{"ID": 1, "opcode": 4}, {"ID": 2, "opcode": 5}, {"ID": 3, "opcode": 6}]
part_=[]
for i in part:
for j in range(32):
if bit_set(i["opcode"],j):
part_.append(copy.copy(i))
part_[-1]["opcode"]=(1<<j)
for i in part_:
print(i)

Related

'if' 'or'- statement in dictionary always returns TRUE

I have this python dictionary:
event_dict = {
'False': 1,
'Hit': 2,
'MP1': 3,
'MP2': 4,
'MP3': 5,
'M_False': 6,
'M_Hit': 7,
'OGT': 8,
'PMC': 9,
'S 4': 10,
'actiCAP Data On': 11,
'boundary': 12
}
And I wrote this code to check if the entries "TriEVE", "TriODD", "TriPMC" are in the dictionary (They're not!):
if "TriEVE" or "TriODD" or "TriPMC" in event_dict:
print('THIS SESSION HAS BAD ANNOTATIONS!!!!!!!')
The code returns:
THIS SESSION HAS BAD ANNOTATIONS!!!!!!!
I tried to use the 'if'-statement with just one input (without 'or'), like:
if "TriEVE" in event_dict:
print('THIS SESSION HAS BAD ANNOTATIONS!!!!!!!')
print(subject)
The code returns nothing, as expected.
Why can't I use 'or'-statements in this case? Is there a smarter way of searching for more than one dictionary entry at once?
In this case, you want
if "TriEVE" in event_dict.keys() or "TriODD" in event_dict.keys() or "TriPMC" in event_dict.keys():
this is because anything not-zero or non-None is evaluated to True in Python
Since it seems that you wanted to search the keys of the dict, you have to use .keys() or .values() if you want to look at values. The object itself isn't useful in this context

Python navigating nested dictionary

I have a nested dictionary that might have non-unique keys
I need to dynamically add/get key-value pairs on this dictionary by their key in string format
The string that is the key name is being read from keyboard input in string format
Given that string I have to find a key that matches it and do something with a corresponding key-value pair
The keys might be non-unique among different nesting levels
But they are unique on a single nesting level
For example, I have this dict:
MyDict = {'a': 1, 'b': 2}
Now, I get some input in string format that tells me to add one more nesting level with key 'c' and then fill it with a key-value pair 'a:3'. I do it like that:
last_edited_element = {'a': 3}
MyDict['c'] = last_edited_element
#MyDict is now {'a': 1, 'b': 2, 'c': {'a': 3}}
Then, I get an input that tells me to do something with a key-value pair that has 'a' key
I am given a rule that first I have to look up for 'a' key in a level that was edited last, then If nothing is found - go one level up. I store my last edited element in a variable last_edited_element.
The last edited element was {'a': 3}, so I do:
if 'a' in last_edited_element:
#do something with {'a': 3}
else:
#go one level up and look for 'a' key there
So the question is, how do I go one level up? I have {a: '3'} stored in a variable last_edited_element, I need to access the upper-level dictionary if any that contains last_edited_element, something like last_edited_element.get_parent_dictionary()
How do I do that?
So following up on my first comment, you could do this:
Initialize a top-level dict
Initialize all children to refer to their parent
Recursively search bottom-up until you find a key or None
example_dict = {'a': 1, 'b': 2, 'parent': None}
example_dict['c'] = {'a': 3, 'parent': example_dict}
def find_key(k, d):
if k in d:
return d[k]
elif d['parent'] is None:
return None
return find_key(k, d['parent'])
print(find_key('a', example_dict['c']))
> 3
print(find_key('b', example_dict['c']))
> 2

Python: assigning and updating items in a list of dictionaries

my_list = []
my_item = {'number': 2}
for value in range(2):
my_list.append(my_item)
print(my_list)
my_list[1]['number'] = 20
print(my_list)
The code above produces the following output:
[{'number': 2}, {'number': 2}]
[{'number': 20}, {'number': 20}]
Question: why are both items in the list changed? This behavior does not occur if I put the assignment statement in line 2 inside the for loop in line 3. But why does it happen in this format?
my_item is a dict object that is located somewhere in memory. When you call my_list.append(my_item), you're putting another reference to that same dict object into the list. No matter how many times you append(my_item), you're referring to the exact same dict object. my_list[1] is just another name for that exact same dict object from before, so mutating my_list[1] will change the dict you see when you reference it using any other name, including my_list[0].
Putting my_item = {'number': 2} inside the for loop solves this problem because it creates a new object for my_item every time, which then gets appended to my_list.

Returning a list of N dictionary keys that have the maximum integer values

my_dict = {'label': 6, 'label_2': 5, 'label_3': 9, 'label_4': 12}
I would like to create a list that will contain the top 2 (or 3, or 4, or 50... this will vary) dictionary keys, according to their highest values. So in the example above if I wanted the top 2, I should get:
['label_3', 'label_4']
for top 3 I should get:
['label', 'label_3', 'label_4']
And so on.
After reading some other stackoverflow threads, I've been experimenting with heapq, but can't get it to work the way I want. Would appreciate some help.
Of course, the moment I post here, I find a solution (thanks to the heapq documentation). This works:
my_list = heapq.nlargest(3, my_dict, key=my_dict.get)
This will go over my_dict and return the keys with the 3 largest values.
Thanks.

Save Results from cursor.callproc in dict

I'm trying to get some data from a MySQL database with a stored procedure and store it in a dict (as mentioned by blair here):
def createProduct(self):
self.cursor.callproc('newProduct')
result = []
for recordset in self.cursor.stored_results():
for row in recordset:
result.append(dict(zip(recordset.column_names,row)))
print(result)
The cursor is created with the option dictionary=True. The output for print(result) is:
[{'manufacturers_id': 0, 'alarm_threshold': 10, 'users_id_tech': 0, 'name': 'item1',
'entities_id': 0, 'notepad': None, 'locations_id': 0, 'groups_id_tech': 0,
'consumableitemtypes_id': 0, 'id': 1, 'comment': '', 'is_deleted': 0, 'ref': ''}]
I tried to access the value of the key name (which is item1) with this code:
print(result['name'])
TypeError: list indices must be integers, not str
and:
print(result(name))
NameError: name 'name' is not defined
I thought the code from blair would create a dict whose values are accessible by keys (for example 'name')? Is this wrong or what am I doing wrong?
Looking at the list of dictionary you posted, I think there is a problem with the way you are printing.
I think this
print(result['name'])
should become this
print(result[0]['name'])
since you are trying to acess a dictionary inside a list.
Hope it works.

Resources