Why is data contamination? - python

# -*- coding: utf-8 -*-
import random, pprint
user = {}
USERINFO_STRUCT = {
'id': '',
}
def client_new(id):
global user
newuser = USERINFO_STRUCT
newuser['id'] = id
user[id] = newuser
pprint.pprint(user)
print ""
client_new(1)
client_new(2)
client_new(3)
I want results:
{1: {'id': 1}}
{1: {'id': 1}, 2: {'id': 2}}
{1: {'id': 1}, 2: {'id': 2}, 3: {'id': 3}}
The results of that code execution is:
{1: {'id': 1}}
{1: {'id': 2}, 2: {'id': 2}}
{1: {'id': 3}, 2: {'id': 3}, 3: {'id': 3}}
How are you doing this?
My machine is Debian Linux 8.6 (Python 2.7.9).

In python, dictionaries and lists are copied by reference:
>>> a = [0]
>>> b = a
>>> b
[0]
>>> a
[0]
>>> b[0] = 2
>>> a
[2]
>>> b
[2]
So, b and a refer to the same list in the python memory and modifying one modifies the other.
So, what you can do is when you want to create another copy of a list or dictionary, make a copy. For a list:
>>> b = a[:] # for a list
For a dictionary:
>>> b = a.copy() # for a dictionary
So, in your code, what you need is to copy the USERINFO_STRUCT into the newuser using newuser = USERINFO_STRUCT.copy()

Related

how to insert list of elements into list of dictionaries

I have one list of elements and another list of dictionaries and i want to insert list of elements into each dictionary of list
list_elem = [1,2,3]
dict_ele = [{"Name":"Madhu","Age":25},{"Name":"Raju","Age:24},{""Name":"Mani","Age":12}],
OUTPUT As:
[{"ID":1,"Name":"Madhu","Age":25},{"ID":2,"Name":"Raju","Age:24},{"ID":3,"Name":"Mani","Age":12}]
I have tried this way :
dit = [{"id":item[0]} for item in zip(sam)]
# [{"id":1,"id":2,"id":3}]
dic1 = list(zip(dit,data))
print(dic1)
# [({"id":1},{{"Name":"Madhu","Age":25}},{"id":2},{"Name":"Raju","Age:24},{"id":3},{""Name":"Mani","Age":12})]
What is the most efficient way to do this in Python?
Making an assumption here that the OP's original question has a typo in the definition of dict_ele and also that list_elem isn't really necessary.
dict_ele = [{"Name":"Madhu","Age":25},{"Name":"Raju","Age":24},{"Name":"Mani","Age":12}]
dit = [{'ID': id_, **d} for id_, d in enumerate(dict_ele, 1)]
print(dit)
Output:
[{'ID': 1, 'Name': 'Madhu', 'Age': 25}, {'ID': 2, 'Name': 'Raju', 'Age': 24}, {'ID': 3, 'Name': 'Mani', 'Age': 12}]
dict_ele = [{"Name":"Madhu","Age":25},{"Name":"Raju","Age":24},{"Name":"Mani","Age":12}]
list_elem = [1,2,3]
[{'ID': id, **_dict} for id, _dict in zip(list_elem, dict_ele)]
[{'ID': 1, 'Name': 'Madhu', 'Age': 25}, {'ID': 2, 'Name': 'Raju', 'Age': 24}, {'ID': 3, 'Name': 'Mani', 'Age': 12}]
try this: r = [{'id':e[0], **e[1]} for e in zip(list_elem, dict_ele)]

Python str not list

I wanted to obtain array of int like [1,2,3]
but got [dict_values([1]),dict_values([2]),dict_values([3])]
My code:
taken_employee_ids_dict = [{'id': 1}, {'id': 2}, {'id': 3}]
taken_employee_ids = [str(taken_employee_ids_list.values()) for taken_employee_ids_list in taken_employee_ids_dict]
in_values_check = ','.join(str(id) for id in taken_employee_ids)
And then in_values_check should go in:
qry = "SELECT CONCAT(first_name, ',', surname) AS full_name, id \
FROM employees \
WHERE date_terminated IS NULL \
and id NOT IN " + "(" + in_values_check + ")" \
" ORDER BY first_name, surname ASC"
sorry i am new to python thanks
For a problem like this, a list comprehension is a commonly applied solution:
taken_employee_ids_dict = [{'id': 1}, {'id': 2}, {'id': 3}]
in_values_check = [employee["id"] for employee in taken_employee_ids_dict]
print(in_values_check)
This outputs
[1, 2, 3]
You can do it with lambda or list comprehension
With Lambda,
taken_employee_ids_dict = [{'id': 1}, {'id': 2}, {'id': 3}]
in_values_check = list(map(lambda x : x['id'], taken_employee_ids_dict))
print(in_values_check)
With List Comprehension,
taken_employee_ids_dict = [{'id': 1}, {'id': 2}, {'id': 3}]
in_values_check = [dic['id'] for dic in taken_employee_ids_dict]
print(in_values_check)
Output:
[1, 2, 3]
You can use something like this.
taken_employee_ids_dict = [{'id': 1}, {'id': 2}, {'id': 3}]
final_list = []
for ele in taken_employee_ids_dict:
for key,value in ele.items():
final_list.append(value)
print(final_list)
Try this:
taken_employee_ids = [str(employee["id"]) for employee in taken_employee_ids_dict]
in_values_check = ','.join(str(id) for id in taken_employee_ids)

Python: How to join dictionaries in for loop

is there any way to join dictionaries as a result in for loop.
Here is my sample code:
for value in data['actions']:
if 'remoteUrls' in value:
url = value['remoteUrls']
ref = value['lastBuiltRevision']['SHA1']
new_dict['url'] = url
new_dict['ref'] = ref
print new_dict
results:
{
'url': [u'ssh://abc.com:29418/abc.git'],
'ref': u'194d4c418c71f77355117bd253cf2ac9849b25dd'
}
{
'url': [u'ssh://def:29418/def.git'],
'ref': u'7a198bf01b73330c379cc54aae1631f4448a4b0b'
}
I want to join the results into one dictionary and the desired output is like this:
{
vcs1: {
'url': [u'ssh://abc.com:29418/abc.git'],
'ref': u'194d4c418c71f77355117bd253cf2ac9849b25dd'
},
vcs2: {
'url': [u'ssh://def:29418/def.git'],
'ref': u'7a198bf01b73330c379cc54aae1631f4448a4b0b'
}
}
Is there any way to achieve the desired output? Any help would be appreciated. Thank you.
This is one way:
lst = [{'url': [u'ssh://abc.com:29418/abc.git'],'ref':u'194d4c418c71f77355117bd253cf2ac9849b25dd'},
{'url': [u'ssh://def:29418/def.git'], 'ref': u'7a198bf01b73330c379cc54aae1631f4448a4b0b'}]
i = (i for i in range(len(lst)))
d = {'vcs{}'.format(next(i) + 1): x for x in lst}
print(d)
# {'vcs1': {'url': ['ssh://abc.com:29418/abc.git'], 'ref': '194d4c418c71f77355117bd253cf2ac9849b25dd'},
# 'vcs2': {'url': ['ssh://def:29418/def.git'], 'ref': '7a198bf01b73330c379cc54aae1631f4448a4b0b'}}
Or using itertools.count as suggested in comments:
from itertools import count
lst = [{'url':[u'ssh://abc.com:29418/abc.git'],'ref':u'194d4c418c71f77355117bd253cf2ac9849b25dd'},
{'url': [u'ssh://def:29418/def.git'], 'ref': u'7a198bf01b73330c379cc54aae1631f4448a4b0b'}]
i = count(1)
d = {'vcs{}'.format(next(i)): x for x in lst}
print(d)
# {'vcs1': {'url': ['ssh://abc.com:29418/abc.git'], 'ref': '194d4c418c71f77355117bd253cf2ac9849b25dd'},
# 'vcs2': {'url': ['ssh://def:29418/def.git'], 'ref': '7a198bf01b73330c379cc54aae1631f4448a4b0b'}}
Or this is even simple using enumerate:
d = {'vcs{}'.format(i): x for i, x in enumerate(lst, 1)}
There are some easy methods,
dict.update() will help you join dictionaries.
>>> a = dict()
>>> a.update({1:2})
>>> a
{1: 2}
>>> a.update({3:4})
>>> a
{1: 2, 3: 4}
dict['key'] = {'url':['URL'], 'ref':'REF'}
>>> a['key123'] = {'url':['url1','url2'], 'ref':'REF'}
>>> a
{1: 2, 'key1': {'a': 'hello'}, 3: 4, 'key123': {'url': ['url1', 'url2'], 'ref': 'REF'}, 'key2': {'url': ['URL1', 'URL2'], 'ref': u'ref'}}
As per your case,
res = dict()
for value in data['actions']:
if 'remoteUrls' in value:
res['key_name'] = {'url':value['remoteUrls'] ,
'ref':value['lastBuiltRevision']['SHA1']}
print res # check the entries
dict comprehension
dict(dict(<key>, {'url':value['remoteUrls'], 'ref':value['lastBuiltRevision']['SHA1']} for value in data['actions'] if 'remoteUrls' in value)

Generate a list of dictonary elements for files in folder

I am making a script that lists the existing files in a directory,and then save them to a dictionary list. In the directory there are two types of images, "foo" and "bar", which at the end of the name have an identifier to know the position in which they should be viewed, for example:
foo_1.jpg
foo_2.jpg
foo_5.jpg
bar_1.jpg
bar_2.jpg
bar_3.jpg
And I want to get the next result:
files = [ {'position': 1, 'foo': '/img/foo_1.jpg','bar': '/img/bar_1.jpg'},
{'position': 2, 'foo': '/img/foo_2.jpg','bar': '/img/bar_2.jpg'},
{'position': 3, 'foo': '','bar': '/img/bar_3.jpg',
{'position': 5, 'foo': '/img/foo_5.jpg','bar': ''} ]
There's my code:
def files_in_folder(folder_name):
folder_path = os.path.join(current_app.config['UPLOAD_FOLDER'], 'files', str(folder_name))
data = []
if not os.path.isdir(folder_path):
return [{}, {}, {}, {}, {}, {}, {}, {}, {}]
else:
for filename in os.listdir(folder_path):
position = int(re.search('[0-9]+', filename).group())
if "foo" in filename:
foo_register = {'position': position,
'foo': folder_path + '/' + filename,
'bar': ''}
else:
bar_register = {'position': position,
'foo': '',
'bar': folder_path + '/' + filename }
register = {**foo_register, **bar_register}
data.insert(position-1, register)
print(data)
My result is:
[{'foo': '', 'bar': 'uploads/campaigns/1/bar_1.png', 'position': 1},
{'foo': '', 'bar': 'uploads/campaigns/1/bar_2.png', 'position': 2},
{'foo': '', 'bar': 'uploads/campaigns/1/bar_3.png', 'position': 3},
{'foo': 'uploads/campaigns/1/foo_1.png', 'bar': '', 'position': 1,
{'foo': '', 'bar': 'uploads/campaigns/1/bar_3.png', 'position': 3}]
What I'm missing in my code?. There's a best pythonic way to do this?
Thanks in advance.
Obviously, I don't have those files on my HD, so here's some code that processes a list of file names, but it shouldn't be hard to adapt it for your purposes.
The heart of this code is a helper function parse_name that extracts the position (pos) and image type info (kind) from a file name.
To organize that info the way you want I put it into a dict of dicts. We then sort the keys of the outer dict to create the desired list of dicts. We use a numeric sort so that 11 doesn't sort before 2, etc.
import os.path
from pprint import pprint
data = '''\
/img/foo_1.jpg
/img/foo_2.jpg
/img/foo_5.jpg
/img/bar_1.jpg
/img/bar_2.jpg
/img/bar_3.jpg
'''.splitlines()
def parse_name(s):
fname = os.path.basename(s)
fbase, _ = os.path.splitext(fname)
kind, pos = fbase.split('_')
return kind, int(pos)
files_dict = {}
for s in data:
kind, pos = parse_name(s)
d = files_dict.setdefault(pos, {'position': pos})
d[kind] = s
pprint(files_dict)
print()
files_list = [files_dict[k] for k in sorted(files_dict.keys(), key=int)]
pprint(files_list)
output
{1: {'bar': '/img/bar_1.jpg', 'foo': '/img/foo_1.jpg', 'position': 1},
2: {'bar': '/img/bar_2.jpg', 'foo': '/img/foo_2.jpg', 'position': 2},
3: {'bar': '/img/bar_3.jpg', 'position': 3},
5: {'foo': '/img/foo_5.jpg', 'position': 5}}
[{'bar': '/img/bar_1.jpg', 'foo': '/img/foo_1.jpg', 'position': 1},
{'bar': '/img/bar_2.jpg', 'foo': '/img/foo_2.jpg', 'position': 2},
{'bar': '/img/bar_3.jpg', 'position': 3},
{'foo': '/img/foo_5.jpg', 'position': 5}]
Actually, we don't need that sort key function, since pos has already been converted to int in parse_name. Oops! :) So we can just do:
files_list = [files_dict[k] for k in sorted(files_dict.keys())]
That for loop could be condensed to:
for s in data:
kind, pos = parse_name(s)
files_dict.setdefault(pos, {'position': pos})[kind] = s
although that's even more cryptic than the previous version. ;)
files_dict.setdefault(pos, {'position': pos})
fetches the sub-dict in files_dict with the key pos. If it doesn't exist, it's created with an initial key-value pair of ('position', pos).
We then update that sub-dict with the (kind, s), where s is the full filename of the the current file.
Try to use filename.startswith('bar') or filename.startswith('foo') to distinguish foo_1.jpg and bar_1.jpg
Try to use position=int(os.path.splitext(filename)[0].split('_')[-1]) instead of re.
Don't use register = {**foo_register, **bar_register} :
e.g.
a={'foo': '', 'bar': 'uploads/campaigns/1/bar_1.png', 'position': 1}
b={'foo': 'uploads/campaigns/1/foo_.png', 'bar': '', 'position': 1}
print({**a,**b})
Output:
{'foo': 'uploads/campaigns/1/foo_.png', 'bar': '', 'position': 1}
I think this is why you got the unexpected result.
You can try this:
a.update({k:v for k,v in b.items() if v})
print(a)
Output:
{'foo': 'uploads/campaigns/1/foo_.png', 'bar': 'uploads/campaigns/1/bar_1.png', 'position': 1}
import os, re
cwd = os.getcwd()
print cwd
def update(li, pos, path, key):
added = False
if len(li) == 0:
di=dict()
di["position"] = int(pos)
di[key] = path
li.append(di)
added = True
else:
for di in li:
if di["position"]==pos:
di[key] = path
added = True
if not added:
di=dict()
di["position"] = int(pos)
di[key] = path
li.append(di)
li = []
for filename in os.listdir(cwd+r'/try'): # folder name where my files are.
position = int(re.search('[0-9]+', filename).group())
print filename, position
path = cwd + '/' + filename
if "foo" in filename:
update(li, position, path, "foo")
elif "bar" in filename:
update(li, position, path, "bar")
print li

Replace keys in a nested dictionary

I have a nested dictionary {1: {2: {3: None}}} and a dictionary that maps keys of the nested dictionary to a set of values such as {1: x, 2: y, 3: z}. I want to transform the nested dictionary to this form {x: {y: {z: None}}}. I have tried a couple of recursive functions but I keep going in circles and confusing myself. What is the best way to achieve this?
The level of nesting is arbitrary. The above is a simple example.
You need to recurse through the dictionary while building a new one with new keys. Note that if you have a list or tuple in there somewhere that has other dictionaries in it, they won't be processed - you'd have to add some code to do that. You can actually do this without building a new dictionary, but I think this way is simpler.
od = { 1: { 2: { 3: None }}}
kd = { 1: 'x', 2: 'y', 3: 'z' }
def replace_keys(old_dict, key_dict):
new_dict = { }
for key in old_dict.keys():
new_key = key_dict.get(key, key)
if isinstance(old_dict[key], dict):
new_dict[new_key] = replace_keys(old_dict[key], key_dict)
else:
new_dict[new_key] = old_dict[key]
return new_dict
nd = replace_keys(od, kd)
print nd
outputs:
{'x': {'y': {'z': None}}}
The accepted answer will not support dict of list, adding the full feature
#bilentor,
od = {'name': 'John', '1': [{'name': 'innername'}]}
kd = { 'name': 'cname', '1': '2', 3: 'z' }
def replace_keys(data_dict, key_dict):
new_dict = { }
if isinstance(data_dict, list):
dict_value_list = list()
for inner_dict in data_dict:
dict_value_list.append(replace_keys(inner_dict, key_dict))
return dict_value_list
else:
for key in data_dict.keys():
value = data_dict[key]
new_key = key_dict.get(key, key)
if isinstance(value, dict) or isinstance(value, list):
new_dict[new_key] = replace_keys(value, key_dict)
else:
new_dict[new_key] = value
return new_dict
nd = replace_keys(od, kd)
print(nd)
You can use a NestedDict
from ndicts import NestedDict
d = {1: {2: {3: None}}}
replace = {1: 'x', 2: 'y', 3: 'z'}
def ndict_replace(ndict: dict, map: dict):
nd = NestedDict(nd)
new_nd = NestedDict()
for key, value in nd.items():
new_key = tuple(replace.get(k, k) for k in key)
new_nd[new_key] = value
return new_nd.to_dict()
>>> ndict_replace(d, replace)
{'x': {'y': {'z': None}}}
The solution is robust and works with any nested dictionary
>>> d = {
1: {2: {3: None}},
3: {4: None},
5: None
}
>>> ndict_replace(d, replace)
{'x': {'y': {'z': None}}, 'z': {4: None}, 4: None}}
To install ndicts pip install ndicts

Categories