Accessing dictionary from function in Python - python

So I'm trying to take variables from one function, and continue to use them in another. I'm getting a KeyError when I try to run this. Any ideas? Cheers!
def find_pos():
x = 1
y = 12
z = 3
return { 'x':x, 'y':y, 'z':z }
def create(x, y, z):
blah = x + y + z
print 'blah'
testReturn = find_pos()
create(testReturn[x], testReturn[y], testReturn[z])

You are trying to access your dictionary by referring to your keys by a variable name that you have not defined. This is incorrect. Your dictionary keys were created using strings 'x', 'y' and 'z'. Therefore, you must access your data in your dictionary as such.
You want to do this:
create(testReturn['x'], testReturn['y'], testReturn['z'])
Better yet, since you seem to be doing some math operations on it, you can even use get instead, which will return None by default if it can't find the key. So, in your case, you can change this default, and set it to 0 instead:
create(testReturn.get('x', 0), testReturn.get('y', 0), testReturn.get('z', 0))

Related

Concatenate strings to form a variable name

I have a number of variables in my python script containing integers e.g.,
lab19 = 100-50 #50
lab20 = 200-20 #180
I have a while loop that loops through an incrementing counter calling a function each time. The function needs to pass the variable, but the 19 and 20 parts of the variable name come from the counter.
I have tried this,
y = 1
while y < 21:
bundleRun('lab' + str(y))
y += 1
but that is passing the literal string 'lab1' value to the function.
How do I get my code to pass the variable value (e.g., 50) to my function based on the counter?
Thanks
I think you should store your data in a list or dict so it can be accessed by index or by key. But if you really need to access a local variable by name you can use locals()
y = 1
while y < 21:
a = locals()['lab' + str(y)] # value stored in variable a
y += 1
Whilst you can do this, you shouldn't.[^1] Dynamically created variables in python are a code smell (unlike e.g. TeX, where this kind of thing is routine).
Instead, store everything in a collection:
results = {"lab19": 50, "lab20": 180}
for lab, result in results.keys():
bundleRun(result)
Note that your while loop could be better written as:
for y in range(1,21):
...
If you really do need to do this, the other answer with locals() is the way to go.
[^1] but it could be worse: you're only trying to access them. Perhaps you have to do this---but if you have control over the variables the pythonic way is to use a collection.

Classes vs. dictionaries as variable containers to get rid of quotation marks?

I’m trying to better understand the concept of python dictionaries and want to use a dictionary as a container of several variables in my code. Most examples I looked for, show strings as dictionary keys, which implies the use of quotation marks for using keys as variables. However, I found out that one does not need to use quotation marks if the key is firstly given a value and after that placed in a dictionary. Then one get rid of the quotation marks. The variable is then actually an immutable value. In that case, even as one changes the value of the key, the original value remains in the key and can be retrieved by dictionary method -.keys() (and thus be used to restore the first given value). However, I’m wondering if this is a proper way of coding and if it is better to apply a class as a variable container, which looks more simple but is perhaps slower when executed. Both approaches lead to the same result. See my example below.
class Container ():
def __init__(self):
self.a = 15
self.b = 17
# first given values
a = 5
b = 7
# dictionary approach
container = {a:15, b:17}
print('values in container: ', container[a], container[b])
container[a], container[b] = 25, 27
print('keys and values in container: ', container[a], container[b])
for key in container.keys():
print('firstly given values: ', key)
print('\n')
# class approach
cont = Container()
print('values in cont: ', cont.a, cont.b)
cont.a, cont.b = 25, 27
print('keys and values in cont: ', cont.a, cont.b)
However, I found out that one does not need to use quotation marks if the key is firstly given a value and after that placed in a dictionary.
This isn’t really what’s happening. Your code isn’t using 'a' and 'b' as dictionary keys. It’s using the values of the variables a and b — which happen to be the integers 5 and 7, respectively.
Subsequent access to the dictionary also happens by value: whether you write container[a] or container[5] doesn’t matter (as long as a is in scope and unchanged). But *it is not the same as container['a'], and the latter would fail here.
You can also inspect the dictionary itself to see that it doesn’t have a key called 'a' (or unquoted, a):
>>> print(dictionary)
{5: 15, 7: 17}
Ultimately, if you want to use names (rather than values) to access data, use a class, not a dictionary. Use a dictionary when the keys are given as values.
Later you may assign other values to a and b, and the code using dictionary will crash. Using a variable as a key is not a good practice. Do it with the class. You may also add the attributes to the constructor of your class.
class Container ():
def __init__(self, a, b):
self.a = a
self.b = b
# creating
cont = Container(15, 17)
# changin
cont.a, cont.b = 25, 27
I would recommand the class approach, because the dict approach in this case does not seem a proper way to code.
When you do :
a = 5
b = 7
container = {a:15, b:17}
You actually do :
container = {5:15, 7:17}
But this is "hidden", so there is a risk that later you reassign your variables, or that you just get confused with this kind of dictionary :
container = {
a:15,
b:17,
"a": "something"
}

Assigning values to objects attributes that don't exist

I'm doing a data mining homework with python(2.7). I created a weight dict for all words(that exist in the category), and for the words that don't exist in this dict, i want to assign a default value.
First I tried with setdefault for everykey before using it, it works perfectly, but somehow I think it doesn't look so pythonic. Therefore I tried using defaultdict, which works just fine most of the time. However, sometimes it returns an incorrect value. First I thought it could be caused by defaultdict or lambda function, but apparently there are no errors.
for node in globalTreeRoot.traverse():
...irrelevant...
weight_dict = {.......}
default_value = 1.0 / (totalwords + dictlen)
node.default_value = 1.0/ (totalwords + dictlen)
......
node.weight_dict_ori = weight_dict
node.weight_dict = defaultdict(lambda :default_value,weight_dict)
So, when I tried to print a value that doesn't exist during the loop, it gives me a correct value. However, after the code finishes running, when I try:
print node.weight_dict["doesnotexist"],
it gives me an incorrect value, and when incorrect usually a value related to some other node. I tried search python naming system or assign values to object attributes dynamically, but didn't figure it out.
By the way, is defaultdict faster than using setdefault(k,v) each time?
This is not a use case of defaultdict.
Instead, simply use get to get values from the dictionary.
val = dict.get("doesnotexist", 1234321)
is perfectly acceptable python "get" has a second parameter, the default value if the key was not found.
If you only need this for "get", defaultdict is a bit overkill. It is meant to be used like this:
example = defaultdict(list)
example[key].append(1)
without having to initialize the key-list combination explicitly each time. For numerical values, the improvements are marginal:
ex1, ex2 = dict, defaultdict(lambda: 0)
ex1[key] = ex1.get(key, 0) + 1
ex2[key] += 1
Your original problem probably is because you reused the variable storing the weight. Make sure it is local to the loop!
var = 1
ex3 = defaultdict(lambda: var)
var = 2
print ex3[123]
is supposed to return the current value of var=2. It's not substituted into the dictionary at initialization, but behaves as if you had define a function at this position, accessing the "outer" variable var.
A hack is this:
def constfunc(x):
return lambda: x
ex3 = defaultdict(constfunc(var))
Now constfunc is evaluated at initialization, x is a local variable of the invocation, and the lambda now will return an x which does not change anymore. I guess you can inline this (untested):
ex3 = defaultdict((lambda x: lambda: x)(var))
Behold, the magics of Python, capturing "closures" and the anomalies of imperative languages pretending to do functional programming.
setdefault is definitely what you should use to set a default value.
for node in globalTreeRoot.traverse():
node.default_value = 1.0 / (totalwords + dictlen)
node.weight_dict = {}
# if you did want to use a defaultdict here for some reason, it would be
# node.weight_dict = defaultdict(lambda: node.default_value)
for word in wordlist:
value = node.weight_dict.setdefault(word, node.default_value)
Apparently, there is something wrong with defaultdict.
d1 = {"a":10,"b":9,"c":8}
seven = 7
d2 = defaultdict(lambda :seven,d1)
seven = 8
d3 = defaultdict(lambda :seven,d1)
And the result:
>>> d2[4234]
8
I still don't understand why it works this way. As for my work, I'll stick with setdefault.
UPDATE:
Thanks for answering. I misunderstood how variable scoping works in Python.

Cannot convert string due to None Error

def draw_constellation_file(file_name):
x = open(file_name)
y = x.read()
y = y.splitlines()
for i in range(0, len(y)):
a = y[i]
b = a.split(',')
aa = str(get_line_for_star_name(b[0]))
cc = get_star_point_from_line(aa)
return aa
get_star_point_from_line looks like this:
def get_star_point_from_line(stardata):
stardata = stardata.split(',')
x = float(stardata[0])
y = float(stardata[1])
return [x, y]
The output:
ValueError: could not convert string to float: None
Here's the thing: the stardata.split doesn't seem to split. I'm sure it has something to do with the None.
Any ideas?
You're passing aa = str(get_line_for_star_name(b[0]))
into get_star_point_from_line(stardata): and that shows you only passing 1 index: b[0].
If b[0] is not a full list and only one string than when you assign x = float(stardata[0])andy = float(stardata[1]) you are trying to assign those variables to indices that dont exist.
If b[0] is a full string it may be splitting up differently than what you thought it would. I would try splitting it using just split() instead of split(',') and then rstrip(',') to get rid of the commas.
Its difficult to pinpoint the problem without knowing what the list looks like when you originally did aa = str(get_line_for_star_name(b[0])). Which by the way is converting that into a string, which you then attempt to reconvert later into a float, which I thought was kind of odd.
It seems there is an error with this code
def get_star_point_from_line(stardata):
stardata = stardata.split(',')
x = float(stardata[0]) //passing string value in float will cause an error
y = float(stardata[1])
return [x, y]
I think the data from the parameter stardata has contained a string value.
in draw_constellation_file, you set b = a.split(',') and pass b[0] to get_line_for_star_name, b[0] will have no ',', so may be you can post the code for get_line_for_star_name to see the reason for the probelm
"None" tends to indicate that nothing is being passed into the function in question. You should make sure that the data you're passing in is what you expect it to be.
In this case, stardata[0] or stardata[1] might not exist. That being said, you need to check the line number to know which one is the problem.

Python references to references in python

I have a function that takes given initial conditions for a set of variables and puts the result into another global variable. For example, let's say two of these variables is x and y. Note that x and y must be global variables (because it is too messy/inconvenient to be passing large amounts of references between many functions).
x = 1
y = 2
def myFunction():
global x,y,solution
print(x)
< some code that evaluates using a while loop >
solution = <the result from many iterations of the while loop>
I want to see how the result changes given a change in the initial condition of x and y (and other variables). For flexibility and scalability, I want to do something like this:
varSet = {'genericName0':x, 'genericName1':y} # Dict contains all variables that I wish to alter initial conditions for
R = list(range(10))
for r in R:
varSet['genericName0'] = r #This doesn't work the way I want...
myFunction()
Such that the 'print' line in 'myFunction' outputs the values 0,1,2,...,9 on successive calls.
So basically I'm asking how do you map a key to a value, where the value isn't a standard data type (like an int) but is instead a reference to another value? And having done that, how do you reference that value?
If it's not possible to do it the way I intend: What is the best way to change the value of any given variable by changing the name (of the variable that you wish to set) only?
I'm using Python 3.4, so would prefer a solution that works for Python 3.
EDIT: Fixed up minor syntax problems.
EDIT2: I think maybe a clearer way to ask my question is this:
Consider that you have two dictionaries, one which contains round objects and the other contains fruit. Members of one dictionary can also belong to the other (apples are fruit and round). Now consider that you have the key 'apple' in both dictionaries, and the value refers to the number of apples. When updating the number of apples in one set, you want this number to also transfer to the round objects dictionary, under the key 'apple' without manually updating the dictionary yourself. What's the most pythonic way to handle this?
Instead of making x and y global variables with a separate dictionary to refer to them, make the dictionary directly contain "x" and "y" as keys.
varSet = {'x': 1, 'y': 2}
Then, in your code, whenever you want to refer to these parameters, use varSet['x'] and varSet['y']. When you want to update them use varSet['x'] = newValue and so on. This way the dictionary will always be "up to date" and you don't need to store references to anything.
we are going to take an example of fruits as given in your 2nd edit:
def set_round_val(fruit_dict,round_dict):
fruit_set = set(fruit_dict)
round_set = set(round_dict)
common_set = fruit_set.intersection(round_set) # get common key
for key in common_set:
round_dict[key] = fruit_dict[key] # set modified value in round_dict
return round_dict
fruit_dict = {'apple':34,'orange':30,'mango':20}
round_dict = {'bamboo':10,'apple':34,'orange':20} # values can even be same as fruit_dict
for r in range(1,10):
fruit_set['apple'] = r
round_dict = set_round_val(fruit_dict,round_dict)
print round_dict
Hope this helps.
From what I've gathered from the responses from #BrenBarn and #ebarr, this is the best way to go about the problem (and directly answer EDIT2).
Create a class which encapsulates the common variable:
class Count:
__init__(self,value):
self.value = value
Create the instance of that class:
import Count
no_of_apples = Count.Count(1)
no_of_tennis_balls = Count.Count(5)
no_of_bananas = Count.Count(7)
Create dictionaries with the common variable in both of them:
round = {'tennis_ball':no_of_tennis_balls,'apple':no_of_apples}
fruit = {'banana':no_of_bananas,'apple':no_of_apples}
print(round['apple'].value) #prints 1
fruit['apple'].value = 2
print(round['apple'].value) #prints 2

Categories