Converting Python dict to kwargs? - python

I want to build a query for sunburnt(solr interface) using class inheritance and therefore adding key - value pairs together. The sunburnt interface takes keyword arguments. How can I transform a dict ({'type':'Event'}) into keyword arguments (type='Event')?

Use the double-star (aka double-splat?) operator:
func(**{'type':'Event'})
is equivalent to
func(type='Event')

** operator would be helpful here.
** operator will unpack the dict elements and thus **{'type':'Event'} would be treated as type='Event'
func(**{'type':'Event'}) is same as func(type='Event') i.e the dict elements would be converted to the keyword arguments.
FYI
* will unpack the list elements and they would be treated as positional arguments.
func(*['one', 'two']) is same as func('one', 'two')

Here is a complete example showing how to use the ** operator to pass values from a dictionary as keyword arguments.
>>> def f(x=2):
... print(x)
...
>>> new_x = {'x': 4}
>>> f() # default value x=2
2
>>> f(x=3) # explicit value x=3
3
>>> f(**new_x) # dictionary value x=4
4

Related

Python set unpacking and pattern matching

If this unpacks a set:
>>> a = {1,2,3}
>>> (x, y, z) = a
>>> x
1
>>> y
2
>>> z
3
Then why the following doesnt?
>>> a = {1,2,3}
>>> match a:
... case (p, q, r):
... print(f'{p} {q} {r}')
...
>>>
I would expect the code above to print "1 2 3".
I understand how sets aren't ordered and I wouldn't be surprised if both didn't work, but the former works, only the latter doesn't.
I've always thought that pattern matching IS based on unpacking.
This is not about types not matching, because if we replace the set {1,2,3} with a list [1,2,3] it would work even though we unpack with a tuple syntax.
match statement sequence patterns have more restrictive rules than sequence unpacking. Sequence unpacking will try to unpack any iterable, but a sequence pattern is specified to require
one of the following:
a class that inherits from collections.abc.Sequence
a Python class that has been registered as a collections.abc.Sequence
a builtin class that has its Py_TPFLAGS_SEQUENCE bit set
a class that inherits from any of the above (including classes defined before a parent’s Sequence registration)
set doesn't meet any of those conditions.
Note that since sets are semantically unordered, there is no guarantee which elements will be assigned to which variables if you try to unpack a set. Your (x, y, z) = a unpacking is not safe.

Unpacking arguments: how to stop a list from turning to a nested list

I have created a function called other_func that results in a list, for example: [12,322,32]
I want to create a function that will receive the other function and it will sort this list. I want to use *args as seen below, to better understand how it works:
def biggest_gap(*args):
result = sorted(args)
return result
The issue is that it results in a nested list:
biggest_gap(other_func(3)) # The use of the other_func does not matter, only that it creates a list of numbers
[[322,32,12]]
If I use the sort() method:
def biggest_gap(*args):
result = args.sort()
return result
returns:
AttributeError: 'tuple' object has no attribute 'sort'
The question is how to stop the 'sorted' approach from creating a nested list and simply create a list or how to make the sort() method not throw an error.
def biggest_gap(*args):
means that args will be a list (well, technically a tuple) of all arguments you gave to the biggest_gap function.
biggest_gap(other_func(3))
will give a list to the biggest_gap function. That's one argument.
So what you get is "a tuple of (a list)".
What you meant to do was giving a multiple individual arguments, by "splatting" the list returned from other_func:
biggest_gap(*other_func(3))
The difference the * makes is
biggest_gap([322, 32, 12]) # without * - biggest_gap receives 1 argument
biggest_gap(*[322, 32, 12]) # with * - biggest_gap receives 3 arguments
biggest_gap(322, 32, 12) # hard-coded equivalent
See https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists
Ok, this is a weird problem with *args in that it returns (in this case) a tuple of args assigned to the variable name args. So, for example, given a function:
def test(*args):
return args
It will return:
>>> test("Hello", "World")
('Hello', 'World')
>>>
A tuple.
Then, sorted, this gets turned into a list.
So, now we can go back and help the original problem, as the nested list comes as a result of the function "other_function" returning a list of 3 numbers, say [1,23,44], and the function is then applied to it.
>>> sorted(test([1,23,44]))
[[1, 23, 44]]
>>>
NB: Tuples don't have a .sort method, instead an alternate method is to use the built in sorted() function.

Why does this print `3 {}` and not `2 {'a': 3}`?

def f(a=2, **b):
print(a,b)
f(**{'a':3})
Why does this print 3 {} and not 2 {'a': 3}?
I can understand why it printed 3 {} if it was f(a=3) but I don't understand the output in this case.
The unpacking operator, when used on a dict, passes the dict's contents as keyword arguments.
In other words, the following two lines are functionally identical:
f(a=3)
f(**{'a':3})
Since a is getting passed explicitly as a keyword argument, the default value of 2 is overwritten. And since no other arguments are passed, the **b argument is left empty.
The call f(**{'a':3}) is same as f(a=3), so the value of a is 3 and not the default 2. For b , using the unpacking operator **, it means to save all the other mapping variable into it, as there is no one, it values an empty dict
a is 3
b is empty dict, {}
So it prints 3 {}
To use b you need to pass argument named differently as a
# both print: 3 {'foo': 'bar', 'number': 100}
f(**{'a':3, 'foo':'bar', 'number':100})
f(a=3, foo='bar', number=100)

How to pass a list in an arg function for being readable in SQL?

I using SQL module in psycopg2 and I'm trying to pass a list as arg a function.
def getSomething(*args):
query = sql.SQL("select col1 from tb1 where col1 in ({})").format(
sql.SQL(', ').join([sql.Literal(ar) for ar in args])
)
print query.as_string(Connection())
Tried in different ways but without success. One of them was, I received a unicode type via POST.
data = request.form['data']
d_array = data.split(',')
print getsomething(d_array)
output d_array [u'66626', u'66635']
InvalidTextRepresentation('invalid input syntax for integer: "66626,66635"\nLINE 9: WHERE col1 in (\'66626,66635\')\n ^\n',)
If I pass these values separated getSomething('66626','66635') works!
My question is about unpack this list in separate values and them put in function as arg or is there another thing to do it?
As mentioned in the comments, the * in python is an unpacking operator, i.e. it unpacks a sequence, if set as a function parameter it effectively allows you to pass an unpacked sequence (i.e. numerous variables and they will all be made available in the function body as the name defined.), however when passed to a function as an argument it unpacks the sequence and passes it to the function as each item individually.
In [1]: def starred(*args):
...: print(type(args))
...: print(args)
...:
In [2]: def pass_starred(arg1, arg2, arg3):
...: print(arg1, arg2, arg3)
...:
In [3]: data = [1, 2, 3]
In [4]: starred(data)
<class 'tuple'>
([1, 2, 3],)
In [5]: pass_starred(*data)
1 2 3
(btw, if you look at the print function, this is how it can print any number of arguments, effectively it gets all non-named arguments as a starred variable and it iterates and prints them.)
The "*" is an unpacking operator in Python.
You don't need unpacking a parameter, if this parameter is a list.
Just remove the "*" before the parameter's name.

Difference call function with asterisk parameter and without

I know what the meaning of an asterisk is in a function definition in Python.
I often, though, see asterisks for calls to functions with parameters like:
def foo(*args, **kwargs):
first_func(args, kwargs)
second_func(*args, **kwargs)
What is the difference between the first and the second function call?
Let args = [1,2,3]:
func(*args) == func(1,2,3) - variables are unpacked out of list (or any other sequence type) as parameters
func(args) == func([1,2,3]) - the list is passed
Let kwargs = dict(a=1,b=2,c=3):
func(kwargs) == func({'a':1, 'b':2, 'c':3}) - the dict is passed
func(*kwargs) == func(('a','b','c')) - tuple of the dict's keys (in random order)
func(**kwargs) == func(a=1,b=2,c=3) - (key, value) are unpacked out of the dict (or any other mapping type) as named parameters
The difference is how the arguments are passed into the called functions. When you use the *, the arguments are unpacked (if they're a list or tuple)—otherwise, they're simply passed in as is.
Here's an example of the difference:
>>> def add(a, b):
... print a + b
...
>>> add(*[2,3])
5
>>> add([2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly 2 arguments (1 given)
>>> add(4, 5)
9
When I prefixed the argument with *, it actually unpacked the list into two separate arguments, which were passed into add as a and b. Without it, it simply passed in the list as a single argument.
The same is the case for dictionaries and **, except they're passed in as named arguments rather than ordered arguments.
>>> def show_two_stars(first, second='second', third='third'):
... print "first: " + str(first)
... print "second: " + str(second)
... print "third: " + str(third)
>>> show_two_stars('a', 'b', 'c')
first: a
second: b
third: c
>>> show_two_stars(**{'second': 'hey', 'first': 'you'})
first: you
second: hey
third: third
>>> show_two_stars({'second': 'hey', 'first': 'you'})
first: {'second': 'hey', 'first': 'you'}
second: second
third: third
def fun1(*args):
""" This function accepts a non keyworded variable length argument as a parameter.
"""
print args
print len(args)
>>> a = []
>>> fun1(a)
([],)
1
# This clearly shows that, the empty list itself is passed as a first argument. Since *args now contains one empty list as its first argument, so the length is 1
>>> fun1(*a)
()
0
# Here the empty list is unwrapped (elements are brought out as separate variable length arguments) and passed to the function. Since there is no element inside, the length of *args is 0
>>>

Categories

Resources