Reputation: 57451
In the code below, I have a dictionary "John" which I assign a value to with a certain key ("phone number"):
John={}
statement='John'+"['phone number']=123456"
exec statement
The reason I did it with "exec" like above is because the actual dictionary "John" and "phone number" are supposed to vary within a for loop. This works, but is not very elegant; I'd rather like to do something similar to
vars()['John'+'_phone_number']=123456
because in this case, you don't run the risk of the "exec" statement failing if the syntax is not right. (What I'd like to achieve is similar to Matlab's "assignin" function, except for dictionary entries).
Is there a way of defining entries of a dictionary without using "exec"?
Upvotes: 1
Views: 125
Reputation: 57451
Although it seems that the majority feels the way to go is using nested dictionaries - and I'll accept this answer - in my own code I decided to stick with the not-so-elegant way using the "exec" statement. The code - which actually is not for users and phone numbers, but is to determine and store mathematical attributes of certain curves - is shown below:
import numpy as np
import matplotlib.pyplot as plt
# CSV file generated from nDI by Data Export -> ASCII with "Export as CSV" ticked on
filename="lnb.1t_LNB-1_wedge_amplitude_extractions.csv"
# Read column headers (to be variable names)
with open(filename) as f:
firstline = f.readline() # Read first line of csv
firstline = firstline.replace("\n","") # Remove new line characters
firstline = firstline.replace(" ","") # Remove spaces
ColumnHeaders = firstline.split(",") # Get array of column headers
# Read in the data (omitting the first row containing column headers)
data=np.loadtxt(filename,skiprows=1,delimiter=",")
N_leg=50 # Number of traces 'pure' gas leg and brine leg
# Assign the data to arrays, with names of the variables generated from column headers
Ind=0 # Initialize counter
for Var in ColumnHeaders:
vars()[Var]=data[:,Ind] # Create an array for each column, named after the corresponding column header
if Var.endswith("_evnt_amp"): # For columns with headers containing the suffix '_evnt_amp' ('event amplitude'):
Event=Var.strip("_evnt_amp") # Define a string containing the event name
vars()[Event]={} # Initialize an empty dictionary
statement1=Event+"['gas leg amplitude']=np.mean(data[0:N_leg,Ind])"
exec statement1
statement2=Event+"['brine leg amplitude']=np.mean(data[-N_leg:-1,Ind])"
exec statement2
statement3=Event+"['gas to brine leg ratio']=np.mean(data[0:N_leg,Ind])/np.mean(data[-N_leg:-1,Ind])"
exec statement3
## vars()[Var+'_gas_leg']=data[0:N_leg,Ind]
## vars()[Var+'_brine_leg']=data[-N_leg:-1,Ind]
## vars()[Var.strip('_evnt_amp')+'_gas_leg_amplitude']=np.mean(data[0:N_leg,Ind])
## vars()[Var.strip('_evnt_amp')+'_brine_leg_amplitude']=np.mean(data[-N_leg:-1,Ind])
Ind=Ind+1 # Increment counter
plt.close('all')
plt.figure(1)
plt.plot(Bin,ROSLU_T_evnt_amp,'c')
plt.plot(Bin,-DC_T_evnt_amp,'m')
plt.xlabel('Bin')
plt.ylabel('|Amplitude|')
plt.legend(['ROSLU_T','DC_T'])
plt.show()
The relevant part is the for loop with the "exec" statements. (I've commented out the 'obsolete' lines below them, which work by appending suffixes instead of creating a dictionary).
After running this code, I can for example at the command line type the name of an event, and read several of its attributes:
>>> ROSLU_T
{'gas to brine leg ratio': 2.1782322499999998, 'gas leg amplitude': 174.25857999999997, 'brine leg amplitude': 80.0}
For reference I've pasted a part of the input csv file below:
Track, Bin, ZEZ2A_T_evnt_amp,RO_T_evnt_amp,ROSLU_T_evnt_amp,DC_T_evnt_amp 1, 1, -1288.4139, 999.9983, 174.1523, -201.6915 1, 2, -1288.4139, 999.9983, 174.1523, -201.6915 1, 3, -1288.4139, 999.9983, 174.1523, -201.6915 1, 4, -1288.4139, 999.9983, 174.1523, -201.6915 1, 5, -1288.4139, 999.9983,
The plot generated by this code is shown below.
Upvotes: 0
Reputation: 113978
I think defaultdict
is a bad idea here ... Im pretty sure all users should have the same keys (eg all users should be a phone number and email , or a user_id or the same keys for every user
users = {}
for name,phone,email in [("john","123","a@b"),("mary","432","b@b"),...]:
users[name] = dict(email=email,phone=phone)
or if you are going to use default dict at least ensure that it has all the required fields of a user
def my_user_dict():
return {"email":"","phone":""}
users = defaultdict(my_user_dict)
Upvotes: 1
Reputation: 47988
I think you should use a dictionary of dictionaries. You can even employ a defaultdict
to avoid needing to precondition each entry for each individual user.
from collections import defaultdict
users = defaultdict(dict)
users['John']['phone number'] = 123456
Upvotes: 4