Deep evaluation of variables - python

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.

Related

Iterate over Python list with clear code - rewriting functions

I've followed a tutorial to write a Flask REST API and have a special request about a Python code.
The offered code is following:
# data list is where my objects are stored
def put_one(name):
list_by_id = [list for list in data_list if list['name'] == name]
list_by_id[0]['name'] = [new_name]
print({'list_by_id' : list_by_id[0]})
It works, which is nice, and even though I understand what line 2 is doing, I would like to rewrite it in a way that it's clear how the function iterates over the different lists. I already have an approach but it returns Key Error: 0
def put(name):
list_by_id = []
list = []
for list in data_list:
if(list['name'] == name):
list_by_id = list
list_by_id[0]['name'] = request.json['name']
return jsonify({'list_by_id' : list_by_id[0]})
My goal with this is also to be able to put other elements, that don't necessarily have the type 'name'. If I get to rewrite the function in an other way I'll be more likely to adapt it to my needs.
I've looked for tools to convert one way of coding into the other and answers in forums before coming here and couldn't find it.
It may not be beatiful code, but it gets the job done:
def put(value):
for i in range(len(data_list)):
key_list = list(data_list[i].keys())
if data_list[i][key_list[0]] == value:
print(f"old value: {key_list[0], data_list[i][key_list[0]]}")
data_list[i][key_list[0]] = request.json[test_key]
print(f"new value: {key_list[0], data_list[i][key_list[0]]}")
break
Now it doesn't matter what the key value is, with this iteration the method will only change the value when it finds in the data_list. Before the code breaked at every iteration cause the keys were different and they played a role.

How to use local varaiable containing a string to reference the name of a Global Variable

I have a script in which I'm trying to iterate through a list of strings, then take the value of the current variable, convert it to upper-case, then use use the result as a variable name. The end result will be to set the value of a prometheus metric, which is a global variable.
from prometheus_client import start_http_server, Gauge
# List of strings (global variables will be equal but upper-case)
MEASUREMENTS = ['x', 'y', 'z']
# Prometheus Metrics set as global variables
X = Gauge('some_value', 'some_description', ['label1', 'label2']
Y = Gauge('some_value', 'some_description', ['label1', 'label2']
Z = Gauge('some_value', 'some_description', ['label1', 'label2']
...
# Iterate through list of strings
for measurement in MEASUREMENTS:
metric = getattr(some_status, measurement) # Will be an integer
upper_measurement = measurement.upper() # Will equal the global variable name
[?UPPER_MEASUREMENT?].labels(label1=value_P1, label_2=value).set(metric) # This is where I need to reference the global variable name
Effectively this:
[?UPPER_MEASUREMENT?].labels(label1=value_P1, label_2=value).set(metric)
Needs to be:
X.labels(label1=value_P1, label_2=value).set(metric)
I tried:
upper_measurement.labels(label1=value_P1, label_2=value).set(metric)
But of course that will result in an error since it's a string:
Error: 'str' object has no attribute 'labels'
Not quite sure where to go from here. I could just write a big ugly block setting each metric, but I'd rather avoid that if possible.
Define your metrics in a dictionary:
METRICS = {
key: Gauge('some_value', 'some_description', ['label1', 'label2'])
for key in ['x', 'y', 'z']
}
and then you can easily update all the metrics by iterating over the dictionary:
for key, metric in METRICS.items():
metric.labels(label1=value_P1, label_2=value).set(getattr(some_status, key))
Even though I think the correct way of doing this should be using a Dictionary as other answers have pointed out, but if you still want to know, you could do this with eval(). So, with just changing
[?UPPER_MEASUREMENT?].labels(label1=value_P1, label_2=value).set(metric)
with
eval(upper_measurement).labels(label1=value_P1, label_2=value).set(metric)
it should work. Beware if you're getting the elements of the MEASUREMENTS list from some input that you can't sanitize before using eval(), because it can potentially run dangerous code.

Python unexpected behaviour with list.append()

I was working with a machine learning model and I tried to append his output in a list for each element in antoher list.
I used a for loop but it seems like the loop jumps the first index and repeats the last ones:
x = [[0.12], [0.36], [0.48]]
print(model.run(x[0])) #this prints [-0.0006]
print(model.run(x[1])) #this prints [-0.0018]
print(model.run(x[2])) #this prints [-0.0024]
out_values = []
for value in x:
out_values.append(model.run(value))
print(out_values) #this should print [[-0.0012], [-0.0018], [-0.0024]]
# but it actually prints [[-0.0018], [-0.0024], [-0.0024]]
It doesn't seem to be a problem with the model.run() output since the first print statements worked perfectly
It must be something related to out_values.append(), because if I run:
x = [[0.12], [0.36], [0.48]]
out_values = []
out_values.append(model.run(x[0]))
out_values.append(model.run(x[1]))
out_values.append(model.run(x[2]))
print(out_values) # the result I get is still [[-0.0018], [-0.0024], [-0.0024]]
In my opinion it wasn't supposed to jump over model.run(x[0]) and repeat model.run(x[2]) twice
Is this documented or supposed to happen? Or am I doing something wrong?
I believe the issue is that model.run is returning a reference to mutable state within the model which is updated on successive run calls -- that's why there's a difference between what you print immediately after the run and what ends up in the list after additional calls. I.e. the value is correct at the time you call append, but it changes after the fact. When you call model.run(x[2]), it's modifying and returning the list that it returned when you called model.run(x[1]), and at some point it also modifies the list that was returned for x[0]. (This is not good behavior IMO -- if model is from an external library, hopefully it's at least documented in the API that you should not keep references to the return value of run! Otherwise it's just plain diabolical.)
To work around this problem so that you can keep each result as it was originally returned, make a copy of each result as you get it:
out_values = [model.run(value).copy() for value in x]
It will not skip any value or repeat any other value twice. Your model.run must be returning those values only. To remove that doubt, can you update the code to print the return value and print that like so:
for value in x:
ans = model.run(value)
print(ans)
out_values.append(ans)
Can you show output for above?
can you use this code instead?
x = (0.12, 0.36, 0.48)
print(x[0]) #this prints [-0.0006]
print(x[1]) #this prints [-0.0018]
print(x[2]) #this prints [-0.0024]
out_values = []
out_values = set(x)
print(out_values)
it'll include all x in the out_values

Why is my dict getting deleted during a dict comprehension constructor?

I'm referencing one dict, protocol_dict, in the dict comprehension construction of another:
for drug_id in drug_dict.keys():
drug_name = Drugs.get_drug_name_from_id(drug_id)
# Error happens here:
frontend_forward_dict[drug_name] = {pid: protocol_dict[pid] for pid in drug_dict[drug_id]}
When I run this code, I get the error message that protocol_dict is not defined. Yet it clearly is, and moreover, when I debug my code, I can verify that python has a stored value for protocol_dict right up until it runs the dict comprehension. But the dict comprehension throws this error the very first time it's called.
When I replaced the dict comprehension with a for-constructor, the problem vanishes, and everything works as expected:
for drug_id in drug_dict.keys():
drug_name = Drugs.get_drug_name_from_id(drug_id)
target_dict = {}
for pid in drug_dict[drug_id]:
target_dict[pid] = protocol_dict[pid]
frontend_forward_dict[drug_name] = target_dict
Does anyone know what's going on here? In case it's useful, here's the definition of protocol_dict:
protocol_dict = {}
for p, val in protocol_data.items():
versions = []
if len(val) == 1:
if "VERSION NUMBER" in val[0]["metadata"].keys():
vers = val[0]["metadata"]["VERSION NUMBER"]
versions.append(vers)
else:
versions.append("-1")
else:
# Multiple versions. Can assume each one comes with the right tag.
for version in val:
vers = version["metadata"]["VERSION NUMBER"]
versions.append(vers)
protocol_dict[p] = versions
protocol_dict needs to be defined before the code that is using it.
Is it defined in the same file, or is it imported?
If it is in the same file then it needs to be in the same scope, you might be defining the protocol_dict in such way that it is not visible by the code that is trying to use it.
There is nothing magical about the dict comprehension, you can test it by running this snipet:
foo = dict(a=1, b=2)
print({x: foo[x] for x in "ab"})

Check if Dictionary Values exist in a another Dictionary in Python

I am trying to compare values from 2 Dictionaries in Python. I want to know if a value from one Dictionary exists anywhere in another Dictionary. Here is what i have so far. If it exists I want to return True, else False.
The code I have is close, but not working right.
I'm using VS2012 with Python Plugin
I'm passing both Dictionary items into the functions.
def NameExists(best_guess, line):
return all (line in best_guess.values() #Getting Generator Exit Error here on values
for value in line['full name'])
Also, I want to see if there are duplicates within best_guess itself.
def CheckDuplicates(best_guess, line):
if len(set(best_guess.values())) != len(best_guess):
return True
else:
return False
As error is about generator exit, I guess you use python 3.x. So best_guess.values() is a generator, which exhaust for the first value in line['full name'] for which a match will not be found.
Also, I guess all usage is incorrect, if you look for any value to exist (not sure, from which one dictinary though).
You can use something like follows, providing line is the second dictionary:
def NameExists(best_guess, line):
vals = set(best_guess.values())
return bool(set(line.values()).intersection(vals))
The syntax in NameExists seems wrong, you aren't using the value and best_guess.values() is returning an iterator, so in will only work once, unless we convert it to a list or a set (you are using Python 3.x, aren't you?). I believe this is what you meant:
def NameExists(best_guess, line):
vals = set(best_guess.values())
return all(value in vals for value in line['full name'])
And the CheckDuplicates function can be written in a shorter way like this:
def CheckDuplicates(best_guess, line):
return len(set(best_guess.values())) != len(best_guess)

Categories

Resources