How to define variables dynamically in python? - python

I need to create variables dynamically based on the data that is coming from my UI.
Sample JSON:
Some of the sample JSON I'll get from UI to hit the python code.
data_json = {'key1':'value1','key2':'value2','key3':['abc','def']}
data_json = {'key1':'value2','key2':'value8','key3':['abc','def','ghi','jklmn']}
data_json = {'key1':'value3','key2':'value9','key3':['abc']}
data_json = {'key1':'value4','key2':'value2','key3':['abc','def','xyz']}
data_json = {'key1':'value6','key2':'value2','key3':['abc','def']}
I have data in JSON format in which the length of the "key3" value will keep changing each time.
I have to capture those values in separate variables and have to use them later in other functions.
If I pass the first data_json first block of if condition will work and assign it to variables. And if I pass the second data_json second block will define the variables.
Python:
secret = data_json['key1']
if secret in ['value1','value6']: ​
​first_value = data_json['key3'][0]
​ second_value = data_json['key3'][1]
if secret in ['value2']:
​ first_value = data_json['key3'][0]
​​ second_value = data_json['key3'][1]
third_value = data_json['key3'][2]
fourth_value = data_json]'key3'][3]
if secret in ['value3']:
first_value = data_json['key3'][0]
if secret in ['value4']:
​ first_value = data_json['key3'][0]
​​ second_value = data_json['key3'][1]
third_value = data_json['key3'][2]
print("Value in first:%s",first_value)
print("Value in second :%s",second_value)
print("Value in third:%s",third_value)
I'm using conditions to capture those variables.The above code is working fine. But I have to avoid using if conditions. Is there any way to define the variables dynamically on the fly and so that i can use it later in same functions?

I don't think you are approaching it the right way. For such cases - where we have unknown number of variables - we use lists! Lists in python are of dynamic size. So, you don't need to know the exact size before creating a list.
Therefore, you can store your numbers in a list and then access them using the indices like this:
all_values = data_json['key3']
print("Value in first:%s", all_-values[0])
print("Value in second :%s", all_values[1])
print("Value in third:%s", all_values[2])
Note that here you don't need conditional statements to make sure you are reading the exact number of values (not more or less) from the JSON.
What you are calling dynamic variables are not needed! Wherever you need first_value, you can use all_values[0]. For, second_value, you can use all_values[1] and so on...

The best way to solve your problem is to save the values in an array and access then via indices, rather than creating separate variables for each element in the array.
data_json = {'key1':'value2','key2':'value8','key3':['abc','def','ghi','jklmn']}
key3_vars = data_json['key3']
for var in key3_vars:
print(var)
But if you have to create separate variables, then you can use the built-in function exec.
data_json = {'key1':'value2','key2':'value8','key3':['abc','def','ghi','jklmn']}
key3_vars = data_json['key3']
for i, var in enumerate(key3_vars):
exec(f"key3_var{i} = '{var}'")
print(key3_var0)
print(key3_var1)
print(key3_var2)
print(key3_var3)

Related

How can I make it so that a value becomes "NULL" if there's an Exception?

I'm storing data from an API (that I then store as a pickle) and sometimes there are errors due to missing fields. I'm wondering how I can make it so that it only targets the problematic variable and logs its value as "NULL".
The issue is that I'm storing 6 different variables, so if a single one of them has an issue, all other 5 variables will be skipped. Instead, I want that (or those) problematic variables get replaced by the value "NULL" (or None).
meta = loaded_from_pickle('myData.pickle')
def getAllData():
data = []
for i in range(len(meta)):
try:
name = meta[i]['base']['name']
weight = meta[i]['base']['weight']
height = meta[i]['base']['height']
age = meta[i]['secondary']['age']
eye_color = meta[i]['secondary']['eye_color']
birthday = meta[i]['secondary']['birthday']
data.append((name, weight, height, age, eye_color, birthday))
except:
pass
return data
print(getAllData())
So what happens is that I end up losing a lot of data points because some data doesn't have "eye_color" or whatnot. So what I should do when there's an "except" should be "make problematic variable = "NULL" ", rather than just passing the entire loop.
Instead of accessing the keys directly using square brackets try using get() it returns a default value of None if the key is not found.
See this answer for more info https://stackoverflow.com/a/11041421/3125312
You could use it in your code:
name = meta[i]['base'].get('name')
weight = meta[i]['base'].get('weight')
height = meta[i]['base'].get('height')
...
You could also rewrite your for loop using enumerate assuming meta is a list
for index, value in enumerate(meta):
name = value['base'].get('name')
...

Deep evaluation of variables

I have a need to use local().update to load some variables from configuration.
The problem is that there are dependencies between them, and i need to evaluate their real values.
For example if run this code:
vars={'x':'z','y':'4','z':'y'}
locals().update(vars)
print (eval(x))
the final result should be x=4, but the assigned value initially is x='y'
def deep(key):
keyChecked = []
while vars[key] in vars.keys() and key not in keyChecked:
keyChecked.append(key)
key = vars[key]
else:
return vars[key]
vars={'x':'z','y':'4','z':'y'}
print(deep('x'))
I think you will get expected answer.

How to call a variable in the name of a new variable

I am relatively new to Python, and I'm wondering how I can call a variable in the name of a new variable.
For example, when I have the 2 following variables and their values:
number1 = 100
string1 = 'abc'
and I want to write a line of code such that I can create new variables who's name contains the values of variables number1 and string1 (e.g new_var_100 and new_var_abc)
For example:
new_var_(value_of_number1) = 200 ##What to write on LHS?
new_var_(value_of_string1) = 'def' ##What to write on LHS?
such that when I call new_var_100, it returns 200; and when I call new_var_abc, it returns 'def'.
Thanks very much.
not realy sure if you shuld do this but here goes:
string1 = 'abc'
globals()[f"string1{number1}]=200```
You can't - at least not without involving some very hacky solutions.
If you want to treat variable names as strings, modifying or concatenating them, you actually want a dictionary:
my_dict = {'number1' = 100, 'string1' = 'abc'}
You then access those values by passing the key values inside brackets - which fundamentally work like arbitrary variable names:
my_dict['number1'] # returns 100
my_dict['string1'] # returns 'abc'
you can then use a simple for loop to create new values based on some logic:
for value in my_dict.values():
my_dict['new_var_' + str(value)] = 200
Note that my code simply sets the values associated with the keys 'new_var_100' and 'new_var_abc' to 200. You'll need extra logic if you want to update strings and ints differently.

How do I use a variable that is built from other variables?

I am trying to build a dynamic URL with some of the information stored in a list. I have loaded the list with some values and then iterate through the list concatenating the value from the list with a prefix. I then want to reference that concatenated value which matches a preloaded variable.
In the below code url_var just returns the name of the variable but not the value of the variable.
base_url_asia = "https://www.location1.com/"
base_url_americas = "https://www.location2.com/"
regions = [asia, americas]
for i in range(len(regions)):
url_var = 'base_url_' + regions[i]
print(url_var)
I expect the output to be the full URL however all I get is base_url_asia or base_url_americas and not the actual url.
You are defining variables that you are not using. 'base_url_' is a string and not a variable. If you want to store different locations using the same variable but with different names, you should use a dictionary.
base_url=dict()
base_url['asia'] = 'www.location1.com'
base_url['americas'] = 'www.location2.com'
continent = ['asia','americas']
for cont in continent:
print(base_url[cont])
Note that cont is not an integer, but is the name of the continents.
I hope you find it useful. Good luck!

Concise way to convert multiple Date Time to seconds?

I am looking for a way to write the code below in a more concise manner. I thought about trying df[timemonths] = pd.to_timedelta(df[timemonths])...
but it did not work (arg must be a string, timedelta, list, tuple, 1-d array, or Series).
Appreciate any help. Thanks
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3',
'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath',
'TimetoRecurrence']
monthsec = 2.628e6 # to convert to months
df.TimetoLocalRecurrence = pd.to_timedelta(df.TimetoLocalRecurrence).dt.total_seconds()/monthsec
df.TimeFromPriorRTtoSRS = pd.to_timedelta(df.TimeFromPriorRTtoSRS).dt.total_seconds()/monthsec
df.TimetoAcuteG3 = pd.to_timedelta(df.TimetoAcuteG3).dt.total_seconds()/monthsec
df.TimetoLateG3 = pd.to_timedelta(df.TimetoLateG3).dt.total_seconds()/monthsec
df.TimeSRStoLastFUDeath = pd.to_timedelta(df.TimeSRStoLastFUDeath).dt.total_seconds()/monthsec
df.TimeDiagnosistoLastFUDeath = pd.to_timedelta(df.TimeDiagnosistoLastFUDeath).dt.total_seconds()/monthsec
df.TimetoRecurrence = pd.to_timedelta(df.TimetoRecurrence).dt.total_seconds()/monthsec
You could write your operation as a lambda function and then apply it to the relevant columns:
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3',
'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath',
'TimetoRecurrence']
monthsec = 2.628e6
convert_to_months = lambda x: pd.to_timedelta(x).dt.total_seconds()/monthsec
df[timemonths] = df[timemonths].apply(convert_to_months)
Granted I am kind of guessing here since you haven't provided any example data to work with.
Iterate over vars() of df
Disclaimer: this solution will most likely only work if the df class doesn't have any other variables.
The way this works is by simply moving the repetitive code after the = to a function.
def convert(times):
monthsec = 2.628e6
return {
key: pd.to_timedelta(value).dt.total_seconds()/monthsec
for key, value in times.items()
}
Now we have to apply this function to each variable.
The problem here is that it can be tedious to apply it to each variable individually, so we could use your list timemonths to apply it based on the keys, however, this requires us to create an array of keys manually like so:
timemonths = ['TimeFromPriorRTtoSRS', 'TimetoAcuteG3','TimetoLateG3', 'TimeSRStoLastFUDeath','TimeDiagnosistoLastFUDeath', 'TimetoRecurrence']
And this can be annoying, especially if you add more, or take away some because you have to keep updating this array.
So instead, let's dynamically iterate over every variable in df
for key, value in convert(vars(df)).items():
setattr(df, key, value)
Full Code:
def convert(times):
monthsec = 2.628e6
return {
key: pd.to_timedelta(value).dt.total_seconds()/monthsec
for key, value in times.items()
}
for key, value in convert(vars(df)).items():
setattr(df, key, value)
Sidenote
The reason I am using setattr is because when examining your code, I came to the conclusion that df was most likely a class instance, and as such, properties (by this I mean variables like self.variable = ...) of a class instance must by modified via setattr and not df['variable'] = ....

Categories

Resources