Pass dictionaries in function as arguments - python

Im trying to create a function that take unknown number of arguments (dictionaries) to merge them in one. Here is my sketch:
weight = {"sara": 60, "nick": 79, "sem": 78, "ida": 56, "kasia": 58, "slava": 95}
height = { "a" : 1, "b": 2, "c":3 }
width = {"u": "long", "q": 55, "qw": "erre", 30: "34"}
a = {10:20, 20:"a"}
def merge(**dict):
new_dict = {}
for x in dict:
for a, b in x.items():
new_dict[a] = b
return new_dict
print(merge(weight, height, width, a))
And I got error:
TypeError: merge() takes 0 positional arguments but 4 were given
Why?

First note: dict is a bad name for an argument as it is already the name of a type.
When you use ** in the argument list for a function it is slurping up any keyword arguments you haven't explicitly listed. Similarly, a parameter with a single * is slurping up any extra positional arguments not explicitly named.
Consider:
>>> def foo(bar, **baz): return (bar, baz)
...
>>> foo(42, wooble=42)
(42, {'wooble': 42})
>>> foo(bar=42, wooble=42)
(42, {'wooble': 42})
>>> foo(bar=42, wooble=42, hello="world")
(42, {'wooble': 42, 'hello': 'world'})
>>>
If you wish to take any number of dictionaries as arguments, you'd use:
def merge(*dicts):
...
As dicts will now slurp up any number of dictionaries passed in.

Change def merge(**dict): to def merge(*dict): and it is working. Avoid naming it dict since it is a keyword in python.

If you want to pass a list of dicts as a single argument you have to do this:
def foo(*dicts)
Anyway you SHOULDN'T name it *dict, since you are overwriting the dict class.
In Python you can pass all the arguments as a list with the * operator...
def foo(*args)
...and as a dict with the ** operator
def bar(**kwargs)
For example:
>>> foo(1, 2, 3, 4) # args is accessible as a list [1, 2, 3, 4]
>>> bar(arg1='hello', arg2='world') # kwargs is accessible as a dict {'arg1'='hello', 'arg2'='world'}
In your case you can edit the prototype of you function this way:
def merge(*dicts):

Related

How can I give an argument without knowing its name to a multiparameter function? Python

Hi I have a multiparameter function where only one parameter is missing in a kwargs and I want to be able to input the missing parameter without knowing what parameter it is:
def function(a,b,c): #multiparameter function
print('a=',a)
print('b=',b)
print('c=',c)
kwargs={'a':1,'b':2} #only the value for c is missing
If I run
function(3,**kwargs) it interprets that a=3 but I want it to interpret that c=3
Alternatively I could find out the name of the missing variable but I cannot manage to feed it correctly to the function. I tried to do:
variable='c'
function(variable=3,**kwargs)
But it returns the error function() got an unexpected keyword argument 'variable'
If you can't modify the definition of function, you can wrap it with functools.partial.
from functools import partial
def function(a,b,c): #multiparameter function
print('a=',a)
print('b=',b)
print('c=',c)
function_caller = partial(function, 1, 2, 3)
Now, any keyword arguments to function_caller will override the values specified in the call to partial:
function_caller() # function(1,2,3)
function_caller(a=5, b=4) # function(5, 4, 3)
kwargs = {'a': 5, 'b': 4}
function_caller(**kwargs) # Same as previous call
If you have variable that contains the name of a parameter, you can easily add that to kwargs, though you can't use it directly as a keyword argument.
variable = 'c'
kwargs = {'a': 5, 'b': 4, variable: 3} # {'a': 5, 'b': 4, 'c': 3}
function_caller, though, does not accept any positional arguments.
First, you should probably read about *args and **kwargs
You can force you parameters to be keyword parameters with * and each of your keyword param can have a default sentinel value to help you spot it.
def function(*,a = None,b = None,c = None)
print('a=',a)
print('b=',b)
print('c=',c)
If you want to input something on the fly you could do:
def function(input, *,a = None,b = None,c = None)
print('a=',a or input)
print('b=',b or input)
print('c=',c or input)
If you can take the parameter as a variable, then this request:
kwargs={'a':1,'b':2} #only the value for c is missing
variable='c'
function(variable=3,**kwargs)
Can work if you just add the variable to the kwargs dictionary:
kwargs[variable] = 3
function(**kwargs)

Python: Cast Dictionary to Tuple implicit by calling a method

I have a problem with Code from the Mininet open source project. I abstracted it to the following scenario:
def bar (*a, **b):
b.update({'a':(a,)})
foo(**b)
def foo (*a, **c):
print(c)
print(a)
if __name__ == '__main__':
bar(2,3,4, x=3, y=5)
Method bar is only a helper to create a function call of foo.
If I run it, print(a) has no output, because the values are still stored in the dictionary b. If I change *a to a, it works fine.
And here my question:
Is there a possibility which does not modify the Method foo which puts data into *a with data and the call of foo is like in line 3? This means only b in method bar is allowed to be modified.
I don't think it's possible to comply both your conditions.
If the method foo stays the same the parameter *a represents a list of arguments with no name (like bar(2,3,4) in your example). And the call to foo(**b) in line 3 means passing keyword args (like bar(x=3, y=5) in your example) so they will be passed to **c as it is the keyword argument in foo.
Ok So I want to make you understand instead of just giving the answer because StackOverflow is all about explaining the concept instead of writing code, let's understand few points :
*args and **kwargs are use as arbitrary number of arguments.
Kwargs ** syntax requires a mapping (such as a dictionary); each
key-value pair in the mapping becomes a keyword argument.
while
*args recieves a tuple containing the positional arguments.
Now let's take simple example to understand your problem:
def check(*a,**b):
print(a)
print(b)
Now *a require a tuple or list or positional argument while **b require dict format keyworded argument.
One more point before jumping into the problem:
*l idiom is to unpack argument lists,tuples,set
a,*b=(1,2,3,4,5)
print(a)
print(b)
output:
1
[2, 3, 4, 5]
Now if i call that function something like:
def check(*a,**b):
print("value_a {}".format(a))
print("value_b {}".format(b))
print(check({'y': 5, 'x': 3, 'a': 5,'r':56}))
Now *a will take the value because there is no keyworded argument :
value_a ({'x': 3, 'y': 5, 'a': 5, 'r': 56},)
But let's add few keywords argument:
print(check({'y': 5, 'x': 3, 'a': 5,'r':56},key_s=5,values=10))
output:
value_a ({'a': 5, 'y': 5, 'r': 56, 'x': 3},)
value_b {'key_s': 5, 'values': 10}
Let's start using unpack method :
print(check(*{'y': 5, 'x': 3, 'a': 5,'r':56}))
output will be:
value_a ('r', 'x', 'y', 'a')
value_b {}
None
Because as i shown you * will unpack the keys of dict and it will treat them as the positional argument not keyworded argument.
Now let's use ** unpacking which will unpack dict as key,value pairs :
I think you got the point , Now let's use ** for mapping dict so it will unpack the dict and each key, value will be keyword argument :
print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))
output:
value_a ()
value_b {'y': 5, 'r': 56, 'a': 5, 'x': 3}
So everything is clear now I think.
Now let's back to your problem :
As you said if you are using:
def check(a,**b):
print("value_a {}".format(a))
print("value_b {}".format(b))
print(check(**{'y': 5, 'x': 3, 'a': 5,'r':56}))
You are getting result because it's taking 'a' value from dict , and rest of values are taken by **b
Now if you want to use *a and **b then you have to provide :
the positional argument for *a
Keyworded argument for **b
As you said you don't want to modify foo then, You can try something like this:
def bar (*a, **b):
foo((a,),**b)
def foo (*a, **c):
print(c)
print(a)
if __name__ == '__main__':
bar(2,3,4, x=3, y=5)
output:
{'y': 5, 'x': 3}
(((2, 3, 4),),)

Preserve nested list structure with itemgetter in Python [duplicate]

Python itemgetter doesn't return tuples of length 0 or 1.
For example:
from operator import itemgetter
def get_something(keys):
d = {
"a": 1,
"b": 2,
"c": 3
}
return itemgetter(*keys)(d)
print(type(get_something(["a", "b"])))
# <class 'tuple'>
print(type(get_something(["a"])))
# <class 'int'>
print(type(get_something([])))
# TypeError: itemgetter expected 1 arguments, got 0
Is there any good reason that the itemgetter is written this way? And not (1,) for the second last () and for the last?
Is there some other built-in option if I always want to return a tuple/list given the keys?
Is there some other built-in option if I always want to return a
tuple/list given the keys?
just use a comprehension:
[d[k] for k in keys]
In context:
from operator import itemgetter
def get_something(keys):
d = {
"a": 1,
"b": 2,
"c": 3
}
return [d[k] for k in keys]
print(get_something(["a", "b"]))
#[1, 2]
print(get_something(["a"]))
#[1]
print(get_something([]))
#[]
Part of your confusion comes from the fact that your get_something() func takes a single argument (expected to be an iterable) and unpacks it when passing it to itemgetter(). This results in the return value of get_something() not being "symetric" with it's arguments.
If you defined get_something() to use varargs instead (as itemgetter() does) :
def get_something(*keys):
d = {
"a": 1,
"b": 2,
"c": 3
}
return itemgetter(*keys)(d)
the return values would be more consistant with the arguments, ie:
# ask for 3 keys, get 3 values:
>>> get_something("a", "b", "c")
(1, 2, 3)
# ask for 2 keys, get 2 values:
>>> get_something("a", "b")
(1, 2)
# ask for one key, get 1 value
>>> get_something("a")
1
# all of this with tuple unpacking in mind:
a, b = get_something("a", "b")
a = get_something("a")
Now the point is that few people would bother using itemgetter() to implement your get_something function - itemgetter has mainly been designed to be used as a callback for sorted() and like functions / methods (where it's current behaviour makes sense), and get_something would more canonically be implemented with a list expression ie:
def get_something(keys):
d = {
"a": 1,
"b": 2,
"c": 3
}
return [d[k] for k in keys]
which would take an iterable and return a (possibly empty) list.
This behavior is documented in the docs (emphasis is mine):
Return a callable object that fetches item from its operand using the
operand’s __getitem__() method. If multiple items are specified,
returns a tuple of lookup values
itemgetter does not decide the return type, it is the operand's __getitem__() method.
Wouldn't it be easier/better
"better" is subjective. You can always wrap itemgetter:
def get_something(keys):
def my_itemgetter():
r = itemgetter(*keys)(d)
return (r,) if type(r) is not tuple else r
d = {
"a": 1,
"b": 2,
"c": 3
}
return my_itemgetter()

How does the double asterik operator work here?

I understand that how * and ** operators generally work. In the following code [ taken from django's source ]
def curry(_curried_func, *args, **kwargs):
def _curried(*moreargs, **morekwargs):
return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs))
return _curried
I get how the args + moreargs part work - the [non - keyword ] arguments passed initially to the function curry and the arguments passed to the curried function returned by curry are combined. What I don't get is how the **dict(kwargs, **morekwargs) works. Could someone please explain that bit?
dict(kwargs, **morekwargs) is a trick (that Guido dislikes) for combining 2 dictionaries into 1.
>>> d = {'foo':'bar'}
>>> kwargs = {'bar':'baz'}
>>> dict(d,**kwargs)
{'foo': 'bar', 'bar': 'baz'}
So, the curried function takes all kwargs passed to curry and adds them to the additional kwargs passed to the _curried function to create a super dictionary. that super dictionary gets unpacked and sent on to the _curried_func.
It effectively builds a union of two dicts, kwargs and morekwargs. Example:
>>> kwargs = {"ham": 1, "spam": 2}
>>> morekwargs = {"spam": 3, "eggs": 2}
>>> dict(kwargs, **morekwargs)
{'eggs': 2, 'ham': 1, 'spam': 3}
This works because the dict constructor takes keyword arguments, so it's the same as
>>> dict(kwargs, spam=3, eggs=2)
{'eggs': 2, 'ham': 1, 'spam': 3}
Finally, the resulting dict is fed as keyword arguments to _curried_func by means of **.

python SyntaxError with dict(1=...), but {1:...} works

Python seems to have an inconsistency in what kind of keys it will accept for dicts. Or, put another way, it allows certain kinds of keys in one way of defining dicts, but not in others:
>>> d = {1:"one",2:2}
>>> d[1]
'one'
>>> e = dict(1="one",2=2)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
Is the {...} notation more fundamental, and dict(...) just syntactic sugar? Is it because there is simply no way for Python to parse dict(1="one")?
I'm curious...
This is not a dict issue, but an artifact of Python syntax: keyword arguments must be valid identifiers, and 1 and 2 are not.
When you want to use anything that is not a string following Python identifier rules as a key, use the {} syntax. The constructor keyword argument syntax is just there for convenience in some special cases.
dict is a function call, and function keywords must be identifiers.
As other answer have stated, dict is a function call. It has three syntactic forms.
The form:
dict(**kwargs) -> new dictionary initialized with the name=value pairs
in the keyword argument list. For example: dict(one=1, two=2)
The keys (or name as used in this case) must be valid Python identifiers, and ints are not valid.
The limitation is not only the function dict You can demonstrate it like so:
>>> def f(**kw): pass
...
>>> f(one=1) # this is OK
>>> f(1=one) # this is not
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
However, there are two other syntactic forms of you can use.
There is:
dict(iterable) -> new dictionary initialized as if via:
d = {}
for k, v in iterable:
d[k] = v
Example:
>>> dict([(1,'one'),(2,2)])
{1: 'one', 2: 2}
And from a mapping:
dict(mapping) -> new dictionary initialized from a mapping object's
(key, value) pairs
Example:
>>> dict({1:'one',2:2})
{1: 'one', 2: 2}
While that may not seem like much (a dict from a dict literal) keep in mind that Counter and defaultdict are mappings and this is how you would covert one of those to a dict:
>>> from collections import Counter
>>> Counter('aaaaabbbcdeffff')
Counter({'a': 5, 'f': 4, 'b': 3, 'c': 1, 'e': 1, 'd': 1})
>>> dict(Counter('aaaaabbbcdeffff'))
{'a': 5, 'c': 1, 'b': 3, 'e': 1, 'd': 1, 'f': 4}
If you read the documentation, you will learn that the dict = {stringA = 1, stringB = 2} notation is valid when the keys are simple strings:
When the keys are simple strings, it is sometimes easier to specify
pairs using keyword arguments:
>>>
>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}
Since integers (or other numbers) are not valid keyword arguments, the dict = {1 = 2, 3 = 4} will fail as any call to a function would if you passed an argument to it while naming it with a number:
>>> def test(**kwargs):
... for arg in kwargs:
... print arg, kwargs[arg]
...
>>> test(a=2,b=3)
a 2
b 3
>>> test(1=2, 3=4)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression

Categories

Resources