a(*{'q':'qqq'}),why only print key - python

def a(*x):
print x
a({'q':'qqq'})
a(*{'q':'qqq'})#why only print key.
traceback:
({'q': 'qqq'},)
('q',)

That's how dictionaries get converted to sequences.
tuple(dictionary) = tuple(dictionary.keys())
for a similar reason
for x in dictionary:
assigns keys, not pairs, to x

When you're calling a function, using an asterisk before a list or dict will pass it in as positional parameters.
For example:
>>> a(*('test', 'testing'))
('test', 'testing')
>>> a(*{'a': 'b', 'c': 'd'})
('a', 'c')

Using * in front of an expression in a function call iterates over the value of the expression (your dict, in this case) and makes each item in the iteration another parameter to the function invocation. Iterating over a dict in Python yields the keys (for better or worse).

Iterating a dictionary will yield its keys.
d = {'a': 1, 'b': 2, 'c': 3 }
for x in d:
print x # prints a, b, c but not necessarily in that order
sorted(d): # Gives a, b, c in that order. No 1/2/3.
If you want to get both keys and values from a dictionary, you can use .items() or .iteritems()
sorted(d.items()) # [('a,' 1), ('b', 2), ('c', 3)]

You are asking for a list of arguments, and then telling python to send a dict as a sequence of arguments. When a dict is converted to a sequence, it uses the keys.
I guess you are really looking for **, not *.

a(*{'q' : 'qqq'})
will try to expand your dict ({'q':'qqq'}) into an itemized list of arguments for the function.
Note that:
tuple({'q' : 'qqq'})
returns ('q',), which is exactly what you're seeing. When you coerce a dictionary to a list/tuple, you only get the list of keys.

Probably because that's what a dictionary returns when you do a standard iteration over it. It gets converted to a sequence containing it's keys. This example exhibits the same behaviour:
>>> for i in {"a": "1", "b": "2"}:
... print i
...
a
b
To get what I assume you expect you would pass it as variable keyword arguments instead, like this:
>>> def a(**kwargs):
... print kwargs
...
>>> a(**{"a": "1", "b": "2"})
{'a': '1', 'b': '2'}
Note that you are now basically back where you began and have gained nothing.

Related

Python: Arguments to sorting function

I am trying to sort a python list of strings. I know that I can use the method sorted and set the attribute key to be a function that implements the behavior I need to sort the elements of the dictionary on. My problem is that this method needs an argument.
UPDATE:
I want the method to generalize to multiple arguments.
Example:
I want to sort a list of strings based on their priorities in 2 dictionaries . So I need to use those priority dictionaries in sorting the list.
I want something like:
sorted(myList, key=sortingAlgorithm(priorityDictionary1, priorityDictionary2), reverse=True)
This can be done if I set the priority dictionaries as global variables and then I will not need to have it as an argument to the sorting algorithm. But, I want to be able to do it without global variables.
If this is not possible, can you please recommend the pythonic way of doing this.
Thanks in advance.
Try key=priorityDictionary.get
get is a method on a dictionary that takes a key and returns a value, if one is found.
Edit: The above solution applies to a case of a single dict. Here is a generalization where values of priorityDict2 are keys for priorityDict1.
And, as Padriac Cunningham points out, you can use a lambda to sort using nested dicts:
output = sorted(myList, key=lambda element: priorityDict1[priorityDict2[element]])
Use a closure.
def something(foo):
def somethingsomething(bar):
return foo(bar)
return somethingsomething
baz = something(len)
print baz('quux')
Code -
priorities = {'xyz' : 1, 'cde' : 3, 'abc' : 4, 'pqr' : 2}
arr = ['abc', 'cde', 'pqr', 'xyz', 'cde', 'abc']
arr.sort(key = lambda s : priorities[s])
print(arr)
Output -
['xyz', 'pqr', 'cde', 'cde', 'abc', 'abc']
Some slightly more standalone examples:
stringList = ["A1", "B3", "C2", "D4"]
priorityDict = {"A1": 1, "B3": 3, "C2": 2, "D4": 4}
# Reference an accessor function
print sorted(stringList, key=priorityDict.get)
# Provide a lambda function (with "free" closure)
print sorted(stringList, key=lambda x: priorityDict[x])
# Provide a normal function (helper definition needs scope visibility
# on priority dict, but doesn't have to be global - you can define
# functions in the scope of other functions a little like lambdas)
def myKey(x):
return priorityDict[x]
print sorted(stringList, key=myKey)
If you want to pass the value from one dict as the key to the next you need a function or a lambda:
l = ["foo", "Foo", "Bar", "bar", "foobar", "Foobar"]
d1 = {"f": 1, "F": 0, "b": 1, "B": 0}
d2 = {1: 10, 0: 20}
print(sorted(l, key=lambda x: d2[d1[x[0]]]))
If a key may not exist you can still use get:
sorted(l, key=lambda x: d2.get(d1.get(x[0], {}), some_default))
Just make sure some_default makes sense and can be compared to the other values.
def sortingAlgorithm(primaryDictionary):
def __cmp__(a, b):
pass # do something with a, b, and primaryDictionary here
return __cmp__

Build a dictionary with a regular expression

I am getting some data through a serial connection which I'd like to process so I can do more with it.
My Python script gets the variable which looks like:
data = "P600F600"
and my goal is to get this:
finaldata = {
'P': 600,
'F': 600
}
I like regular expressions and my input format is very strict so I've devised this RegEx to grab the data:
/([A-Z])(\d+)/
Based on my limited knowledge of Python, I've devised this.
finadata = eval( '{' + re.sub(r"([A-Z])(\d+)", r"'\1':\2,", data) + '}' )
but this is clearly a horrible and extremely hacky solution.
In this case, re.findall seems to be really helpful:
>>> import re
>>> re.findall('([A-Z])(\d+)', 'P600F600')
[('P', '600'), ('F', '600')]
It just so happens that a dict can be built from this directly:
>>> dict(re.findall('([A-Z])(\d+)', 'P600F600'))
{'P': '600', 'F': '600'}
Of course, this leaves you with string values rather than integer values. To get ints, you'd need to construct them more explicitly:
>>> items = re.findall('([A-Z])(\d+)', 'P600F600')
>>> {key: int(value) for key, value in items}
{'P': 600, 'F': 600}
Or for python2.6- compatibility:
>>> dict((key, int(value)) for key, value in items)
{'P': 600, 'F': 600}
Since findall already returns sequence of two-element sequences:
re.findall('([A-Z])(\d+)', data) # [('P', '600'), ('F', '600')]
You may simply use dict built-in function:
import re
dict(re.findall('([A-Z])(\d+)', data)) # {'P': '600', 'F': '600'}
Quoting docs:
If no positional argument is given, an empty dictionary is created. If
a positional argument is given and it is a mapping object, a
dictionary is created with the same key-value pairs as the mapping
object. Otherwise, the positional argument must be an iterable object.
Each item in the iterable must itself be an iterable with exactly two
objects. The first object of each item becomes a key in the new
dictionary, and the second object the corresponding value. If a key
occurs more than once, the last value for that key becomes the
corresponding value in the new dictionary.

using a single variable to index into nested dictionaries

Imagine you have a dictionary in python: myDic = {'a':1, 'b':{'c':2, 'd':3}}. You can certainly set a variable to a key value and use it later, such as:
myKey = 'b'
myDic[myKey]
>>> {'c':2, 'd':3}
However, is there a way to somehow set a variable to a value that, when used as a key, will dig into sub dictionaries as well? Is there a way to accomplish the following pseudo-code in python?
myKey = "['b']['c']"
myDic[myKey]
>>> 2
So first it uses 'b' as a key, and whatever is reurned it then uses 'c' as a key on that. Obviously, it would return an error if the value returned from the first lookup is not a dictionary.
No, there is nothing you can put into a variable so that myDict[myKey] will dig into the nested dictionaries.
Here is a function that may work for you as an alternative:
def recursive_get(d, keys):
if len(keys) == 1:
return d[keys[0]]
return recursive_get(d[keys[0]], keys[1:])
Example:
>>> myDic = {'a':1, 'b':{'c':2, 'd':3}}
>>> recursive_get(myDic, ['b', 'c'])
2
No, not with a regular dict. With myDict[key] you can only access values that are actually values of myDict. But if myDict contains other dicts, the values of those nested dicts are not values of myDict.
Depending on what you're doing with the data structure, it may be possible to get what you want by using tuple keys instead of nested dicts. Instead of having myDic = {'b':{'c':2, 'd':3}}, you could have myDic = {('b', 'c'):2, ('b', 'd'): 3}. Then you can access the values with something like myDic['b', 'c']. And you can indeed do:
val = 'b', 'c'
myDic[val]
AFAIK, you cannot. If you think about the way python works, it evaluates inside out, left to right. [] is a shorthand for __getitem__ in this case. Thus you would need to parse the arguments you are passing into __getitem__ (whatever you pass in) and handle that intelligently. If you wanted to have such behavior, you would need to subclass/write your own dict class.
myDict = {'a':1, 'b':{'c':2, 'd':3}}
k = 'b'
myDict.get(k) should give
{'c':2, 'd':3}
and either
d.get(k)['c']
OR
k1 = 'c'
d.get(k).key(k1) should give 2
Pretty old question. There is no builtin function for that.
Compact solution using functools.reduce and operator.getitem:
from functools import reduce
from operator import getitem
d = {'a': {'b': ['banana', 'lemon']}}
p = ['a', 'b', 1]
v = reduce(getitem, p, d)
# 'lemon'

retrieving keys from dictionaries depending on value in python

I'm trying to find the most efficient way in python to create a dictionary of 'guids' (point ids in rhino) and retrieve them depending on the value(s) I assign them, change that value(s) and restoring them back in the dictionary. One catch is that with Rhinoceros3d program the points have a random generated ID number which I don't know so I can only call them depending on the value I give them.
are dictionaries the correct way? should the guids be the value instead of the keys?
a very basic example :
arrPts=[]
arrPts = rs.GetPoints() # ---> creates a list of point-ids
ptsDict = {}
for ind, pt in enumerate(arrPts):
ptsDict[pt] = ('A'+str(ind))
for i in ptsDict.values():
if '1' in i :
print ptsDict.keys()
how can I make the above code print the key that has the value '1' , instead of all the keys? and then change the key's value from 1 to e.g. 2 ?
any help also on the general question would be appreciated to know I'm in the right direction.
Thanks
Pav
You can use dict.items().
An example:
In [1]: dic={'a':1,'b':5,'c':1,'d':3,'e':1}
In [2]: for x,y in dic.items():
...: if y==1:
...: print x
...: dic[x]=2
...:
a
c
e
In [3]: dic
Out[3]: {'a': 2, 'b': 5, 'c': 2, 'd': 3, 'e': 2}
dict.items() returns a list of tuples containing keys and value pairs in python 2.x:
In [4]: dic.items()
Out[4]: [('a', 2), ('c', 2), ('b', 5), ('e', 2), ('d', 3)]
and in python 3.x it returns an iterable view instead of list.
I think you want the GUID's to be values, not keys, since it looks like you want to look them up by something you assign. ...but it really depends on your use case.
# list of GUID's / Rhinoceros3d point ids
arrPts = ['D20EA4E1-3957-11d2-A40B-0C5020524153',
'1D2680C9-0E2A-469d-B787-065558BC7D43',
'ED7BA470-8E54-465E-825C-99712043E01C']
# reference each of these by a unique key
ptsDict = dict((i, value) for i, value in enumerate(arrPts))
# now `ptsDict` looks like: {0:'D20EA4E1-3957-11d2-A40B-0C5020524153', ...}
print(ptsDict[1]) # easy to "find" the one you want to print
# basically make both keys: `2`, and `1` point to the same guid
# Note: we've just "lost" the previous guid that the `2` key was pointing to
ptsDict[2] = ptsDict[1]
Edit:
If you were to use a tuple as the key to your dict, it would look something like:
ptsDict = {(loc, dist, attr3, attr4): 'D20EA4E1-3957-11d2-A40B-0C5020524153',
(loc2, dist2, attr3, attr4): '1D2680C9-0E2A-469d-B787-065558BC7D43',
...
}
As you know, tuples are immutable, so you can't change the key to your dict, but you can remove one key and insert another:
oldval = ptsDict.pop((loc2, dist2, attr3, attr4)) # remove old key and get value
ptsDict[(locx, disty, attr3, attr4)] = oldval # insert it back in with a new key
In order to have one key point to multiple values, you'd have to use a list or set to contain the guids:
{(loc, dist, attr3, attr4): ['D20E...', '1D2680...']}

Destructuring-bind dictionary contents

I am trying to 'destructure' a dictionary and associate values with variables names after its keys. Something like
params = {'a':1,'b':2}
a,b = params.values()
But since dictionaries are not ordered, there is no guarantee that params.values() will return values in the order of (a, b). Is there a nice way to do this?
from operator import itemgetter
params = {'a': 1, 'b': 2}
a, b = itemgetter('a', 'b')(params)
Instead of elaborate lambda functions or dictionary comprehension, may as well use a built in library.
One way to do this with less repetition than Jochen's suggestion is with a helper function. This gives the flexibility to list your variable names in any order and only destructure a subset of what is in the dict:
pluck = lambda dict, *args: (dict[arg] for arg in args)
things = {'blah': 'bleh', 'foo': 'bar'}
foo, blah = pluck(things, 'foo', 'blah')
Also, instead of joaquin's OrderedDict you could sort the keys and get the values. The only catches are you need to specify your variable names in alphabetical order and destructure everything in the dict:
sorted_vals = lambda dict: (t[1] for t in sorted(dict.items()))
things = {'foo': 'bar', 'blah': 'bleh'}
blah, foo = sorted_vals(things)
How come nobody posted the simplest approach?
params = {'a':1,'b':2}
a, b = params['a'], params['b']
Python is only able to "destructure" sequences, not dictionaries. So, to write what you want, you will have to map the needed entries to a proper sequence. As of myself, the closest match I could find is the (not very sexy):
a,b = [d[k] for k in ('a','b')]
This works with generators too:
a,b = (d[k] for k in ('a','b'))
Here is a full example:
>>> d = dict(a=1,b=2,c=3)
>>> d
{'a': 1, 'c': 3, 'b': 2}
>>> a, b = [d[k] for k in ('a','b')]
>>> a
1
>>> b
2
>>> a, b = (d[k] for k in ('a','b'))
>>> a
1
>>> b
2
Here's another way to do it similarly to how a destructuring assignment works in JS:
params = {'b': 2, 'a': 1}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
What we did was to unpack the params dictionary into key values (using **) (like in Jochen's answer), then we've taken those values in the lambda signature and assigned them according to the key name - and here's a bonus - we also get a dictionary of whatever is not in the lambda's signature so if you had:
params = {'b': 2, 'a': 1, 'c': 3}
a, b, rest = (lambda a, b, **rest: (a, b, rest))(**params)
After the lambda has been applied, the rest variable will now contain:
{'c': 3}
Useful for omitting unneeded keys from a dictionary.
Hope this helps.
Maybe you really want to do something like this?
def some_func(a, b):
print a,b
params = {'a':1,'b':2}
some_func(**params) # equiv to some_func(a=1, b=2)
If you are afraid of the issues involved in the use of the locals dictionary and you prefer to follow your original strategy, Ordered Dictionaries from python 2.7 and 3.1 collections.OrderedDicts allows you to recover you dictionary items in the order in which they were first inserted
(Ab)using the import system
The from ... import statement lets us desctructure and bind attribute names of an object. Of course, it only works for objects in the sys.modules dictionary, so one could use a hack like this:
import sys, types
mydict = {'a':1,'b':2}
sys.modules["mydict"] = types.SimpleNamespace(**mydict)
from mydict import a, b
A somewhat more serious hack would be to write a context manager to load and unload the module:
with obj_as_module(mydict, "mydict_module"):
from mydict_module import a, b
By pointing the __getattr__ method of the module directly to the __getitem__ method of the dict, the context manager can also avoid using SimpleNamespace(**mydict).
See this answer for an implementation and some extensions of the idea.
One can also temporarily replace the entire sys.modules dict with the dict of interest, and do import a, b without from.
Warning 1: as stated in the docs, this is not guaranteed to work on all Python implementations:
CPython implementation detail: This function relies on Python stack frame support
in the interpreter, which isn’t guaranteed to exist in all implementations
of Python. If running in an implementation without Python stack frame support
this function returns None.
Warning 2: this function does make the code shorter, but it probably contradicts the Python philosophy of being as explicit as you can. Moreover, it doesn't address the issues pointed out by John Christopher Jones in the comments, although you could make a similar function that works with attributes instead of keys. This is just a demonstration that you can do that if you really want to!
def destructure(dict_):
if not isinstance(dict_, dict):
raise TypeError(f"{dict_} is not a dict")
# the parent frame will contain the information about
# the current line
parent_frame = inspect.currentframe().f_back
# so we extract that line (by default the code context
# only contains the current line)
(line,) = inspect.getframeinfo(parent_frame).code_context
# "hello, key = destructure(my_dict)"
# -> ("hello, key ", "=", " destructure(my_dict)")
lvalues, _equals, _rvalue = line.strip().partition("=")
# -> ["hello", "key"]
keys = [s.strip() for s in lvalues.split(",") if s.strip()]
if missing := [key for key in keys if key not in dict_]:
raise KeyError(*missing)
for key in keys:
yield dict_[key]
In [5]: my_dict = {"hello": "world", "123": "456", "key": "value"}
In [6]: hello, key = destructure(my_dict)
In [7]: hello
Out[7]: 'world'
In [8]: key
Out[8]: 'value'
This solution allows you to pick some of the keys, not all, like in JavaScript. It's also safe for user-provided dictionaries
With Python 3.10, you can do:
d = {"a": 1, "b": 2}
match d:
case {"a": a, "b": b}:
print(f"A is {a} and b is {b}")
but it adds two extra levels of indentation, and you still have to repeat the key names.
Look for other answers as this won't cater to the unexpected order in the dictionary. will update this with a correct version sometime soon.
try this
data = {'a':'Apple', 'b':'Banana','c':'Carrot'}
keys = data.keys()
a,b,c = [data[k] for k in keys]
result:
a == 'Apple'
b == 'Banana'
c == 'Carrot'
Well, if you want these in a class you can always do this:
class AttributeDict(dict):
def __init__(self, *args, **kwargs):
super(AttributeDict, self).__init__(*args, **kwargs)
self.__dict__.update(self)
d = AttributeDict(a=1, b=2)
Based on #ShawnFumo answer I came up with this:
def destruct(dict): return (t[1] for t in sorted(dict.items()))
d = {'b': 'Banana', 'c': 'Carrot', 'a': 'Apple' }
a, b, c = destruct(d)
(Notice the order of items in dict)
An old topic, but I found this to be a useful method:
data = {'a':'Apple', 'b':'Banana','c':'Carrot'}
for key in data.keys():
locals()[key] = data[key]
This method loops over every key in your dictionary and sets a variable to that name and then assigns the value from the associated key to this new variable.
Testing:
print(a)
print(b)
print(c)
Output
Apple
Banana
Carrot
An easy and simple way to destruct dict in python:
params = {"a": 1, "b": 2}
a, b = [params[key] for key in ("a", "b")]
print(a, b)
# Output:
# 1 2
I don't know whether it's good style, but
locals().update(params)
will do the trick. You then have a, b and whatever was in your params dict available as corresponding local variables.
Since dictionaries are guaranteed to keep their insertion order in Python >= 3.7, that means that it's complete safe and idiomatic to just do this nowadays:
params = {'a': 1, 'b': 2}
a, b = params.values()
print(a)
print(b)
Output:
1
2

Categories

Resources