Python: Cast Dictionary to Tuple implicit by calling a method - python

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),),)

Related

passing dynamically all dictionary <key, value> as function arguments

i got a given dictionary - for instance:
x = {'a': 1,'b': 2, 'c': 3}
what i would like to do is sending all keys and values to some function.
for instance:
func1(a=1,b=2,c=3)
(for other dictionary y = {'z': 8,'x': 9, 'w': 11,'p': 88}
the function call will be:
func1(z=8,x=9,w=11,p=88))
is it possible?
Thank you.
This is a built in feature of python, consider the following:
x = {'a': 1,'b': 2, 'c': 3}
func1(**x)
is the same as:
func1(a=1, b=2, c=3)
I recommend you read the documentation on defining fuctions
These exemples might be useful. However it really depends on what's the final function
How to pass dictionary items as function arguments in python?
https://www.geeksforgeeks.org/python-passing-dictionary-as-arguments-to-function/
How to pass dictionary as an argument of function and how to access them in the function

Pass dictionaries in function as arguments

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):

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)

How to build arguments for a python function in a variable

I have a Python (3) function
def f(a, b, c=1, d=2):
pass
I would like to build up a list of arguments in code. The actual use-case is to do this based on some command line argument parsing, but it's a general question (I'm fairly new to python) e.g.
myargs = {}
myargs['positionalParams'] = ['foo', 'bar']
myargs['c']=2
myargs['d']=3
f(myargs)
I know that I can do f(*somelist) to expand a list into separate args, but how to do that with a mix of positional and optional params? Or do I do it twice, once for positionals and once for a dict of others?
args = ['foo', 'bar']
kwargs = {'c': 2, 'd': 3}
f(*args, **kwargs)
Note that this will also do just fine:
kwargs = {'a': 'foo', 'b': 'bar', 'c': 2, 'd': 3}
f(**kwargs)
how to do that with a mix of positional and optional params?
You can pass values to positional arguments also with a dictionary by unpacking it like this
>>> def func(a, b, c=1, d=2):
... print(a, b, c, d)
...
...
>>> myargs = {"a": 4, "b": 3, "c": 2, "d": 1}
>>> func(**myargs)
4 3 2 1
Or do I do it twice, once for positionals and once for a dict of others?
Yes. You can unpack the values for the positional arguments also, like this
>>> pos_args = 5, 6
>>> keyword_args = {"c": 7, "d": 8}
>>> func(*pos_args, **keyword_args)
5 6 7 8
Or you might choose to pass the values explicitly, like this
>>> func(9, 10, **keyword_args)
9 10 7 8

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