Most concise way to create a python dictionary from local variables - python

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.

Related

How to create multiple data members for a class in python using a loop..? [duplicate]

I want to use a bunch of local variables defined in a function, outside of the function. So I am passing x=locals() in the return value.
How can I load all the variables defined in that dictionary into the namespace outside the function, so that instead of accessing the value using x['variable'], I could simply use variable.
Rather than create your own object, you can use argparse.Namespace:
from argparse import Namespace
ns = Namespace(**mydict)
To do the inverse:
mydict = vars(ns)
Consider the Bunch alternative:
class Bunch(object):
def __init__(self, adict):
self.__dict__.update(adict)
so if you have a dictionary d and want to access (read) its values with the syntax x.foo instead of the clumsier d['foo'], just do
x = Bunch(d)
this works both inside and outside functions -- and it's enormously cleaner and safer than injecting d into globals()! Remember the last line from the Zen of Python...:
>>> import this
The Zen of Python, by Tim Peters
...
Namespaces are one honking great idea -- let's do more of those!
This is perfectly valid case to import variables in
one local space into another local space as long as
one is aware of what he/she is doing.
I have seen such code many times being used in useful ways.
Just need to be careful not to pollute common global space.
You can do the following:
adict = { 'x' : 'I am x', 'y' : ' I am y' }
locals().update(adict)
blah(x)
blah(y)
Importing variables into a local namespace is a valid problem and often utilized in templating frameworks.
Return all local variables from a function:
return locals()
Then import as follows:
r = fce()
for key in r.keys():
exec(key + " = r['" + key + "']")
The Bunch answer is ok but lacks recursion and proper __repr__ and __eq__ builtins to simulate what you can already do with a dict. Also the key to recursion is not only to recurse on dicts but also on lists, so that dicts inside lists are also converted.
These two options I hope will cover your needs (you might have to adjust the type checks in __elt() for more complex objects; these were tested mainly on json imports so very simple core types).
The Bunch approach (as per previous answer) - object takes a dict and converts it recursively. repr(obj) will return Bunch({...}) that can be re-interpreted into an equivalent object.
class Bunch(object):
def __init__(self, adict):
"""Create a namespace object from a dict, recursively"""
self.__dict__.update({k: self.__elt(v) for k, v in adict.items()})
def __elt(self, elt):
"""Recurse into elt to create leaf namespace objects"""
if type(elt) is dict:
return type(self)(elt)
if type(elt) in (list, tuple):
return [self.__elt(i) for i in elt]
return elt
def __repr__(self):
"""Return repr(self)."""
return "%s(%s)" % (type(self).__name__, repr(self.__dict__))
def __eq__(self, other):
if hasattr(other, '__dict__'):
return self.__dict__ == other.__dict__
return NotImplemented
# Use this to allow comparing with dicts:
#return self.__dict__ == (other.__dict__ if hasattr(other, '__dict__') else other)
The SimpleNamespace approach - since types.SimpleNamespace already implements __repr__ and __eq__, all you need is to implement a recursive __init__ method:
import types
class RecursiveNamespace(types.SimpleNamespace):
# def __init__(self, /, **kwargs): # better, but Python 3.8+
def __init__(self, **kwargs):
"""Create a SimpleNamespace recursively"""
self.__dict__.update({k: self.__elt(v) for k, v in kwargs.items()})
def __elt(self, elt):
"""Recurse into elt to create leaf namespace objects"""
if type(elt) is dict:
return type(self)(**elt)
if type(elt) in (list, tuple):
return [self.__elt(i) for i in elt]
return elt
# Optional, allow comparison with dicts:
#def __eq__(self, other):
# return self.__dict__ == (other.__dict__ if hasattr(other, '__dict__') else other)
The RecursiveNamespace class takes keyword arguments, which can of course come from a de-referenced dict (ex **mydict)
Now let's put them to the test (argparse.Namespace added for comparison, although it's nested dict is manually converted):
from argparse import Namespace
from itertools import combinations
adict = {'foo': 'bar', 'baz': [{'aaa': 'bbb', 'ccc': 'ddd'}]}
a = Bunch(adict)
b = RecursiveNamespace(**adict)
c = Namespace(**adict)
c.baz[0] = Namespace(**c.baz[0])
for n in ['a', 'b', 'c']:
print(f'{n}:', str(globals()[n]))
for na, nb in combinations(['a', 'b', 'c'], 2):
print(f'{na} == {nb}:', str(globals()[na] == globals()[nb]))
The result is:
a: Bunch({'foo': 'bar', 'baz': [Bunch({'aaa': 'bbb', 'ccc': 'ddd'})]})
b: RecursiveNamespace(foo='bar', baz=[RecursiveNamespace(aaa='bbb', ccc='ddd')])
c: Namespace(foo='bar', baz=[Namespace(aaa='bbb', ccc='ddd')])
a == b: True
a == c: True
b == c: False
Although those are different classes, because they both (a and b) have been initialized to equivalent namespaces and their __eq__ method compares the namespace only (self.__dict__), comparing two namespace objects returns True. For the case of comparing with argparse.Namespace, for some reason only Bunch works and I'm unsure why (please comment if you know, I haven't looked much further as types.SimpleNameSpace is a built-in implementation).
You might also notice that I recurse using type(self)(...) rather than using the class name - this has two advantages: first the class can be renamed without having to update recursive calls, and second if the class is subclassed we'll be recursing using the subclass name. It's also the name used in __repr__ (type(self).__name__).
EDIT 2021-11-27:
Modified the Bunch.__eq__ method to make it safe against type mismatch.
Added/modified optional __eq__ methods (commented out) to allow comparing with the original dict and argparse.Namespace(**dict) (note that the later is not recursive but would still be comparable with other classes as the sublevel structs would compare fine anyway).
Used following snippet (PY2) to make recursive namespace from my dict(yaml) configs:
class NameSpace(object):
def __setattr__(self, key, value):
raise AttributeError('Please don\'t modify config dict')
def dump_to_namespace(ns, d):
for k, v in d.iteritems():
if isinstance(v, dict):
leaf_ns = NameSpace()
ns.__dict__[k] = leaf_ns
dump_to_namespace(leaf_ns, v)
else:
ns.__dict__[k] = v
config = NameSpace()
dump_to_namespace(config, config_dict)
There's Always this option, I don't know that it is the best method out there, but it sure does work. Assuming type(x) = dict
for key, val in x.items(): # unpack the keys from the dictionary to individual variables
exec (key + '=val')

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'])

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

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.

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'])

Why does Pycharm's inspector complain about "d = {}"?

When initializing a dictionary with d = {} Pycharm's code inspector generates a warning, saying
This dictionary creation could be rewritten as a dictionary literal.
If I rewrite it d = dict() the warning goes away. Since {} already is a dictionary literal, I'm pretty sure the message is erroneous. Furthermore, it seems like both d = {} and d = dict() are valid and Pythonic.
This related question seems to conclude that the choice is just a matter of style/preference:
differences between "d = dict()" and "d = {}"
Why would Pycharm complain about d = {}?
UPDATE:
Mac nailed it. The warning actually applied to multiple lines, not just the one that was flagged.
Pycharm seems to look for a sequence of consecutive statements where you initialize a dictionary and then set values in the dictionary. For example, this will trigger the warning:
d = {}
d['a'] = 1
But this code will not:
d = {}
pass
d['a'] = 1
What is the code following your dictionary declaration?
I think PyCharm will trigger the error if you have something like:
dic = {}
dic['aaa'] = 5
as you could have written
dic = {'aaa': 5}
Note: The fact that the error goes away if you use the function dict(). This doesn't necessarily mean that pycharm believes dict() is a literal. It could just mean that it doesn't complain about it:
dic = dict()
dic['aaa'] = 5
This can be disabled in the Project Settings or Default Settings.
Navigate to Settings -> Inspections -> Python
Uncheck "Dictionary creation could be rewritten by dictionary literal"
for those who like (just like me) to initialize dictionaries with single operation
d = {
'a': 12,
'b': 'foo',
'c': 'bar'
}
instead of many lines like
d = dict()
d['a'] = 12
d['b'] = ....
in the end I ended up with this:
d = dict()
d.update({
'a': 12,
'b': 'foo',
'c': 'bar'
})
Pycharm is not complaining on this
mydict = {
a: 5,
b:z+c/2
}
The dictionary could have been created directly without initialising them first and then reassigning new values.
I have a situation where this warning is bugging the hell out of me. In my case, I'm populating my dict partially as literals and partially from a tuple output by a function, like so:
def get_other_values():
return 3, 4
foo = {
"a": 1,
"b": 2
}
foo["c"], foo["d"] = get_other_values()
So, unless I create interim vars for the output of get_other_values, PEP8 generates this warning even though I'm creating the dict with literals. And I can't assign the c and d keys in the literal, since the values are output as a tuple.

Categories