Set dictionary value to a variable, not the variable's value - python

In [1]: a = None
In [2]: b = None
In [3]: A = {'a': a, 'b': b}
In [4]: A
Out[4]: {'a': None, 'b': None}
In [5]: a = 1
In [6]: A
Out[6]: {'a': None, 'b': None}
I am trying to assign a reference to a variable to a dictionary value. I don't want to assign the variable's value to the dictionary's value. Is there someway to do this? Basically, I would want the last line to read:
{'a': 1, 'b': None}

This is the closest you will get with python in my opinion:
class myobj:
def __init__(self):
self.mystr=""
#property
def mystr(self):
return self.mystr
#mystr.setter
def mystr(self, val):
self.mystr=val
def __repr__(self):
return str(self)
def __str__(self):
return self.mystr
a = myobj()
a.mystr = 'a'
names={'a': a}
print names
a.mystr = 'b'
print names

No, because integers are immutable in Python. See Python data model for details. You can only change the dictionary value as in:
A['a'] = 1
When you set a = 1, you are actually creating a new a, which is why it does not reflected to the dictionary. From the documentation:
Types affect almost all aspects of object behavior. Even the importance of object identity is affected in some sense: for immutable types, operations that compute new values may actually return a reference to any existing object with the same type and value, while for mutable objects this is not allowed. E.g., after a = 1; b = 1, a and b may or may not refer to the same object with the value one, depending on the implementation, but after c = []; d = [], c and d are guaranteed to refer to two different, unique, newly created empty lists. (Note that c = d = [] assigns the same object to both c and d.)

Python has no support for references. Even in functions, all method parameters are pass-by-value. You can pass a mutable data structure into a function and modify the data structure, but what you describe is impossible.

Let me explain in a little different way. Hope this will be helpful if you are new to python:
Let me use a list object(mutable) to get different id for different object.
>>> a = [1]
>>> id(a)
4405572168
>>> A = {'a': a}
>>> id(A['a'])
4405572168
>>>
So far we got the same id of the a and A['a'].
Now lets bind another object into the name a
>>>
>>> a = {1: 2}
>>> id(a)
140196067104096
>>> id(A['a'])
4405572168
>>>
In the above eg, i bind a new dict object into a and check the identity of a and A['a'] and now they are different as the name a is bind to a totally new object.
Here is another explanation with reference counting:
>>> a = [1]
>>> sys.getrefcount(a)
2
>>> A = {'a': a}
>>> sys.getrefcount(a)
3
>>>
>>> a = {1: 2}
>>> sys.getrefcount(a)
2
>>>
Can you see the decrease in reference counting after we re-bind to a new name, which means its a totally new object bind to a. So, you wont' see the changes on A.
Variable assignment in other language is Name binding in python.

Related

Can you replace a dictionary value with one key lookup?

I would like to know whether there is a more efficient way of replacing a particular value in a dictionary. By "more efficient" I mean to avoid looking up the same key twice. I don't expect it would make a big difference, but I find myself doing the following alot:
foo = {'a': 0, 'b': 1}
foo['b'] = bar(foo['b'])
Update
I think the assignment above is "looking up the same key twice" because the following prints "Hashing b" three times.
class LoudKey:
def __init__(self, key):
self.key = key
def __hash__(self):
print(f'Hashing {self.key}')
return self.key.__hash__()
b = LoudKey('b')
foo = {'a': 0, b: 1}
# first "Hashing b"
foo[b] = float(foo[b])
# next two "Hashing b"s
If dict.__getitem__ and dict.__setitem__ are really not duplicating effort somehow, an elaboration on that would also be accepted as an answer.
You can do it by making the dictionary items a mutable type, then mutating it. The simplest is a list with a single element.
>>> b = LoudKey('b')
>>> foo = {'a': [0], b: [1]}
Hashing b
>>> ref = foo[b]
Hashing b
>>> ref[0] = float(ref[0])
>>> foo
{'a': [0], <__main__.LoudKey object at 0x0000000014C66F40>: [1.0]}
You're right that it wouldn't make much difference in practice, though.

Converting all dictionary key/items pairs to separate lists [duplicate]

This question already has answers here:
Elegant way to unpack limited dict values into local variables in Python
(5 answers)
Closed 9 months ago.
Is there a Pythonic way to assign the values of a dictionary to its keys, in order to convert the dictionary entries into variables?
I tried this out:
>>> d = {'a':1, 'b':2}
>>> for key,val in d.items():
exec('exec(key)=val')
exec(key)=val
^
SyntaxError: invalid syntax
I am certain that the key-value pairs are correct because they were previously defined as variables by me before. I then stored these variables in a dictionary (as key-value pairs) and would like to reuse them in a different function. I could just define them all over again in the new function, but because I may have a dictionary with about 20 entries, I thought there may be a more efficient way of doing this.
You can do it in a single line with:
>>> d = {'a': 1, 'b': 2}
>>> locals().update(d)
>>> a
1
However, you should be careful with how Python may optimize locals/globals access when using this trick.
Note
I think editing locals() like that is generally a bad idea. If you think globals() is a better alternative, think it twice! :-D
Instead, I would rather always use a namespace.
With Python 3 you can:
>>> from types import SimpleNamespace
>>> d = {'a': 1, 'b': 2}
>>> n = SimpleNamespace(**d)
>>> n.a
1
If you are stuck with Python 2 or if you need to use some features missing in types.SimpleNamespace, you can also:
>>> from argparse import Namespace
>>> d = {'a': 1, 'b': 2}
>>> n = Namespace(**d)
>>> n.a
1
If you are not expecting to modify your data, you may as well consider using collections.namedtuple, also available in Python 3.
This was what I was looking for:
>>> d = {'a':1, 'b':2}
>>> for key,val in d.items():
exec(key + '=val')
You already have a perfectly good dictionary. Just use that. If you know what the keys are going to be, and you're absolutely sure this is a reasonable idea, you can do something like
a, b = d['a'], d['b']
but most of the time, you should just use the dictionary. (If using the dictionary is awkward, you are probably not organizing your data well; ask for help reorganizing it.)
you can use operator.itemgetter
>>> from operator import itemgetter
>>> d = {'a':1, 'b':2}
>>> a, b = itemgetter('a', 'b')(d)
>>> a
1
>>> b
2
Consider the "Bunch" solution in Python: load variables in a dict into namespace. Your variables end up as part of a new object, not locals, but you can treat them as variables instead of dict entries.
class Bunch(object):
def __init__(self, adict):
self.__dict__.update(adict)
d = {'a':1, 'b':2}
vars = Bunch(d)
print vars.a, vars.b
Python has great support for list unpacking, but not dict or object unpacking. The most unsurprising and Pythonic approach seems to be accessing each item by hand to build an intermediate tuple as described in this answer:
a, b = d['a'], d['b']
However, if you have a lot of properties, or variable names are long, it can get nasty to do:
great, wow, awesome = dictionary['great'], dictionary['wow'], dictionary['awesome']
For context, the JavaScript equivalent of the above (destructuring) is:
const {great, wow, awesome} = dictionary;
Here's an option that is a bit more dynamic:
>>> dictionary = dict(great=0, wow=1, awesome=2)
>>> great, wow, awesome = (dictionary[k] for k in ("great", "wow", "awesome"))
>>> great
0
>>> awesome
2
This is still verbose; you could write a function to abstract things a bit, but unfortunately you still have to type everything twice:
>>> def unpack(dct, *keys):
... return (dct[k] for k in keys)
...
>>> dictionary = dict(great=0, wow=1, awesome=2)
>>> great, wow, awesome = unpack(dictionary, "great", "wow", "awesome")
You can generalize this to work on objects too:
>>> def unpack(x, *keys):
... if isinstance(x, dict):
... return (x[k] for k in keys)
... return (getattr(x, k) for k in keys)
...
>>> from collections import namedtuple
>>> Foo = namedtuple("Foo", "a b c d e")
>>> foo = Foo(a=0, b=1, c=2, d=3, e=4)
>>> c, b, d, a = unpack(foo, "c", "b", "d", "a")
>>> d
3
After all is said and done, unpacking by hand on multiple lines is probably best for real production code that you need to be safe and comprehensible:
>>> great = dictionary["great"]
>>> wow = dictionary["wow"]
>>> awesome = dictionary["awesome"]
Use pandas:
import pandas as pd
var=pd.Series({'a':1, 'b':2})
#update both keys and variables
var.a=3
print(var.a,var['a'])

Python: modify variable stored as a value in a dictionary

I have the following situation:
>>> a = 1
>>> d = {"a": a}
>>> d
{'a': 1}
>>> d["a"] = 2
>>> d
{'a': 2}
>>> a
1
Of course this is the desired behaviour. However, when I assign 2 to the key "a" of the dictionary d, I would like to know if I can access the variable a instead of its value to modify the value of the variable a directly, accessing it through the dictionary. I.e. my expected last output would be
>>> a
2
Is there any way of doing this?
I suppose you know the idea of mutable and immutable objects. Immutable objects (str, int, float, etc) are passed by value. That's why your desired behaviour can't work. When you do:
a = 1
d["a"] = a
you just pass the value of a variable to your dict key 'a'. d['a'] knows nothing about variable a. They just both point to same primitive value in memory.
I don't know your case and why you need this behaviour, but you can try to use mutable object.
For example:
class A:
def __init__(self, a: int):
self._value = a
#property
def value(self) -> int:
return self._value
#value.setter
def value(self, a: int):
# you can put some additional logic for setting new value
self._value = a
def __int__(self) -> int:
return self._value
And then you can use it in this way:
>>> a = A(1)
>>> d = {"a": a}
>>> d['a'].value
1
>>> d["a"].value = 2
>>> d['a'].value
2
>>> a.value
2
>>> int(a)
2
But it still seems like an overhead and you should rethink whether you really need this behaviour.
When you do
>>> a
, you are calling the value of the variable, a that you set on the first line. You have not changed the value of that variable, hence the output of 1. If you did
>>> d["a"]
, your output would be
>>> 2
. If you want this value to be the variable a's value too, set the value of a to the value of d["a"].
Example-
>>> a = 1
>>> d = {"a": a}
>>> d
{'a': 1}
>>> d["a"] = 2
>>> d
{'a': 2}
>>> a = d["a"]
>>> a
2

Convert dictionary entries into variables [duplicate]

This question already has answers here:
Elegant way to unpack limited dict values into local variables in Python
(5 answers)
Closed 9 months ago.
Is there a Pythonic way to assign the values of a dictionary to its keys, in order to convert the dictionary entries into variables?
I tried this out:
>>> d = {'a':1, 'b':2}
>>> for key,val in d.items():
exec('exec(key)=val')
exec(key)=val
^
SyntaxError: invalid syntax
I am certain that the key-value pairs are correct because they were previously defined as variables by me before. I then stored these variables in a dictionary (as key-value pairs) and would like to reuse them in a different function. I could just define them all over again in the new function, but because I may have a dictionary with about 20 entries, I thought there may be a more efficient way of doing this.
You can do it in a single line with:
>>> d = {'a': 1, 'b': 2}
>>> locals().update(d)
>>> a
1
However, you should be careful with how Python may optimize locals/globals access when using this trick.
Note
I think editing locals() like that is generally a bad idea. If you think globals() is a better alternative, think it twice! :-D
Instead, I would rather always use a namespace.
With Python 3 you can:
>>> from types import SimpleNamespace
>>> d = {'a': 1, 'b': 2}
>>> n = SimpleNamespace(**d)
>>> n.a
1
If you are stuck with Python 2 or if you need to use some features missing in types.SimpleNamespace, you can also:
>>> from argparse import Namespace
>>> d = {'a': 1, 'b': 2}
>>> n = Namespace(**d)
>>> n.a
1
If you are not expecting to modify your data, you may as well consider using collections.namedtuple, also available in Python 3.
This was what I was looking for:
>>> d = {'a':1, 'b':2}
>>> for key,val in d.items():
exec(key + '=val')
You already have a perfectly good dictionary. Just use that. If you know what the keys are going to be, and you're absolutely sure this is a reasonable idea, you can do something like
a, b = d['a'], d['b']
but most of the time, you should just use the dictionary. (If using the dictionary is awkward, you are probably not organizing your data well; ask for help reorganizing it.)
you can use operator.itemgetter
>>> from operator import itemgetter
>>> d = {'a':1, 'b':2}
>>> a, b = itemgetter('a', 'b')(d)
>>> a
1
>>> b
2
Consider the "Bunch" solution in Python: load variables in a dict into namespace. Your variables end up as part of a new object, not locals, but you can treat them as variables instead of dict entries.
class Bunch(object):
def __init__(self, adict):
self.__dict__.update(adict)
d = {'a':1, 'b':2}
vars = Bunch(d)
print vars.a, vars.b
Python has great support for list unpacking, but not dict or object unpacking. The most unsurprising and Pythonic approach seems to be accessing each item by hand to build an intermediate tuple as described in this answer:
a, b = d['a'], d['b']
However, if you have a lot of properties, or variable names are long, it can get nasty to do:
great, wow, awesome = dictionary['great'], dictionary['wow'], dictionary['awesome']
For context, the JavaScript equivalent of the above (destructuring) is:
const {great, wow, awesome} = dictionary;
Here's an option that is a bit more dynamic:
>>> dictionary = dict(great=0, wow=1, awesome=2)
>>> great, wow, awesome = (dictionary[k] for k in ("great", "wow", "awesome"))
>>> great
0
>>> awesome
2
This is still verbose; you could write a function to abstract things a bit, but unfortunately you still have to type everything twice:
>>> def unpack(dct, *keys):
... return (dct[k] for k in keys)
...
>>> dictionary = dict(great=0, wow=1, awesome=2)
>>> great, wow, awesome = unpack(dictionary, "great", "wow", "awesome")
You can generalize this to work on objects too:
>>> def unpack(x, *keys):
... if isinstance(x, dict):
... return (x[k] for k in keys)
... return (getattr(x, k) for k in keys)
...
>>> from collections import namedtuple
>>> Foo = namedtuple("Foo", "a b c d e")
>>> foo = Foo(a=0, b=1, c=2, d=3, e=4)
>>> c, b, d, a = unpack(foo, "c", "b", "d", "a")
>>> d
3
After all is said and done, unpacking by hand on multiple lines is probably best for real production code that you need to be safe and comprehensible:
>>> great = dictionary["great"]
>>> wow = dictionary["wow"]
>>> awesome = dictionary["awesome"]
Use pandas:
import pandas as pd
var=pd.Series({'a':1, 'b':2})
#update both keys and variables
var.a=3
print(var.a,var['a'])

Most concise way to create a python dictionary from local variables

In Objective-C, you can use the NSDictionaryOfVariableBindings macro to create a dictionary like this
NSString *foo = #"bar"
NSString *flip = #"rar"
NSDictionary *d = NSDictionaryOfVariableBindings(foo, flip)
// d -> { 'foo' => 'bar', 'flip' => 'rar' }
Is there something similar in python? I often find myself writing code like this
d = {'foo': foo, 'flip': flip}
# or
d = dict(foo=foo, flip=flip)
Is there a shortcut to do something like this?
d = dict(foo, flip) # -> {'foo': 'bar', 'flip': 'rar'}
No, this shortcut in python does not exist.
But perhaps this is what you need:
>>> def test():
... x = 42
... y = 43
... return locals()
>>> test()
{'y': 43, 'x': 42}
Also, python provides globals() and vars() build-in functions for such things.
See the doc.
have you tried vars()
vars([object])
Return the __dict__ attribute for a module, class, instance, or any other object with a __dict__ attribute.
Objects such as modules and instances have an updateable __dict__
attribute; however, other objects may have write restrictions on their
__dict__ attributes (for example, new-style classes use a dictproxy to prevent direct dictionary updates).
so
variables = vars()
dictionary_of_bindings = {x:variables[x] for x in ("foo", "flip")}
Python doesn't quite have a way to do this, though it does have the functions locals and globals which can give you access to the entire local or global namespace. But if you want to pick out selected variables, I consider it better to use inspect. Here's a function that should do that for you:
def compact(*names):
caller = inspect.stack()[1][0] # caller of compact()
vars = {}
for n in names:
if n in caller.f_locals:
vars[n] = caller.f_locals[n]
elif n in caller.f_globals:
vars[n] = caller.f_globals[n]
return vars
Make sure to check that it works in whatever Python environment you're using. Usage would be like so:
a = 1
b = 2
def func():
c = 3
d = 4
compact('b', 'd') # returns {'b': 2, 'd': 4}
I don't think there's any way to get away without the quotes around the variable names, though.

Categories