What does single(not double) asterisk * means when unpacking dictionary in Python? - python

Can anyone explain the difference when unpacking the dictionary using single or double asterisk? You can mention their difference when used in function parameters, only if it is relevant here, which I don't think so.
However, there may be some relevance, because they share the same asterisk syntax.
def foo(a,b)
return a+b
tmp = {1:2,3:4}
foo(*tmp) #you get 4
foo(**tmp) #typeError: keyword should be string. Why it bothers to check the type of keyword?
Besides, why the key of dictionary is not allowed to be non-string when passed as function arguments in THIS situation? Are there any exceptions? Why they design Python in this way, is it because the compiler can't deduce the types in here or something?

When dictionaries are iterated as lists the iteration takes the keys of it, for example
for key in tmp:
print(key)
is the same as
for key in tmp.keys():
print(key)
in this case, unpacking as *tmp is equivalent to *tmp.keys(), ignoring the values. If you want to use the values you can use *tmp.values().
Double asterisk is used for when you define a function with keyword parameters such as
def foo(a, b):
or
def foo(**kwargs):
here you can store the parameters in a dictionary and pass it as **tmp. In the first case keys must be strings with the names of the parameter defined in the function firm. And in the second case you can work with kwargs as a dictionary inside the function.

def foo(a,b)
return a+b
tmp = {1:2,3:4}
foo(*tmp) #you get 4
foo(**tmp)
In this case:
foo(*tmp) mean foo(1, 3)
foo(**tmp) mean foo(1=2, 3=4), which will raise an error since 1 can't be an argument. Arg must be strings and (thanks # Alexander Reynolds for pointing this out) must start with underscore or alphabetical character. An argument must be a valid Python identifier. This mean you can't even do something like this:
def foo(1=2, 3=4):
<your code>
or
def foo('1'=2, '3'=4):
<your code>
See python_basic_syntax for more details.

It is a Extended Iterable Unpacking.
>>> def add(a=0, b=0):
... return a + b
...
>>> d = {'a': 2, 'b': 3}
>>> add(**d)#corresponding to add(a=2,b=3)
5
For single *,
def add(a=0, b=0):
... return a + b
...
>>> d = {'a': 2, 'b': 3}
>>> add(*d)#corresponding to add(a='a',b='b')
ab
Learn more here.

I think the ** double asterisk in function parameter and unpacking dictionary means intuitively in this way:
#suppose you have this function
def foo(a,**b):
print(a)
for x in b:
print(x,"...",b[x])
#suppose you call this function in the following form
foo(whatever,m=1,n=2)
#the m=1 syntax actually means assign parameter by name, like foo(a = whatever, m = 1, n = 2)
#so you can also do foo(whatever,**{"m":1,"n":2})
#the reason for this syntax is you actually do
**b is m=1,n=2 #something like pattern matching mechanism
so b is {"m":1,"n":2}, note "m" and "n" are now in string form
#the function is actually this:
def foo(a,**b): # b = {"m":1,"n":2}
print(a)
for x in b: #for x in b.keys(), thanks to #vlizana answer
print(x,"...",b[x])
All the syntax make sense now. And it is the same for single asterisk. It is only worth noting that if you use single asterisk to unpack dictionary, you are actually trying to unpack it in a list way, and only key of dictionary are unpacked.

[https://docs.python.org/3/reference/expressions.html#calls]
A consequence of this is that although the *expression syntax may appear after explicit keyword arguments, it is processed before the keyword arguments (and any **expression arguments – see below). So:
def f(a, b):
print(a, b)
f(b=1, *(2,))
f(a=1, *(2,))
#Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
#TypeError: f() got multiple values for keyword argument 'a'
f(1, *(2,))

Related

Why can I not call this function using a variable as an argument in Python?

Example:
def somerando(a,b,c,d):
if not a+b+c+d == 9000:
return (a+b+c+d)
somerando(1,2,3,4)
Returns: 10
but
randonumbs = [1,2,3,4]
somerando(randonumbs)
Gives the following error:
TypeError Traceback (most recent call
last) in
----> 1 somerando(randonumbs)
TypeError: somerando() missing 3 required positional arguments: 'b',
'c', and 'd'
your function expects 4 arguments. randonumbs = [1,2,3,4] is a list (of four items); that is one argument for your function.
you could do this:
randonumbs = [1,2,3,4]
somerando(*randonumbs)
this usage of the asterisk (*) is discussed in this question or in PEP 3132.
You passed randonumbs as list, means this whole list is considered as first argument to the function somerando
You can use somerando(*randonumbs) .
Here, * means pass as tuple & ** means pass as dictionary (key, value pair) if you use ** in function parameters/ arguments.
Thank you.
The single-asterisk form of *args can be used as a parameter to send a non-keyworded variable-length argument list to functions, like below
randonumbs = [1,2,3,4]
somerando(*randonumbs)
The double asterisk form of **kwargs is used to pass a keyworded, variable-length argument dictionary to a function.
randonumbs = {'a':1, 'b':2, 'c': 3, 'd': 4}
somerando(**randonumbs)

custom sort function in python 3 [duplicate]

In Python 2.x, I could pass custom function to sorted and .sort functions
>>> x=['kar','htar','har','ar']
>>>
>>> sorted(x)
['ar', 'har', 'htar', 'kar']
>>>
>>> sorted(x,cmp=customsort)
['kar', 'htar', 'har', 'ar']
Because, in My language, consonents are comes with this order
"k","kh",....,"ht",..."h",...,"a"
But In Python 3.x, looks like I could not pass cmp keyword
>>> sorted(x,cmp=customsort)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'cmp' is an invalid keyword argument for this function
Is there any alternatives or should I write my own sorted function too?
Note: I simplified by using "k", "kh", etc. Actual characters are Unicodes and even more complicated, sometimes there is vowels comes before and after consonents, I've done custom comparison function, So that part is ok. Only the problem is I could not pass my custom comparison function to sorted or .sort
Use the key keyword and functools.cmp_to_key to transform your comparison function:
sorted(x, key=functools.cmp_to_key(customsort))
Use the key argument (and follow the recipe on how to convert your old cmp function to a key function).
functools has a function cmp_to_key mentioned at docs.python.org/3.6/library/functools.html#functools.cmp_to_key
A complete python3 cmp_to_key lambda example:
from functools import cmp_to_key
nums = [28, 50, 17, 12, 121]
nums.sort(key=cmp_to_key(lambda x, y: 1 if str(x)+str(y) < str(y)+str(x) else -1))
compare to common object sorting:
class NumStr:
def __init__(self, v):
self.v = v
def __lt__(self, other):
return self.v + other.v < other.v + self.v
A = [NumStr("12"), NumStr("121")]
A.sort()
print(A[0].v, A[1].v)
A = [obj.v for obj in A]
print(A)
Instead of a customsort(), you need a function that translates each word into something that Python already knows how to sort. For example, you could translate each word into a list of numbers where each number represents where each letter occurs in your alphabet. Something like this:
my_alphabet = ['a', 'b', 'c']
def custom_key(word):
numbers = []
for letter in word:
numbers.append(my_alphabet.index(letter))
return numbers
x=['cbaba', 'ababa', 'bbaa']
x.sort(key=custom_key)
Since your language includes multi-character letters, your custom_key function will obviously need to be more complicated. That should give you the general idea though.
I don't know if this will help, but you may check out the locale module. It looks like you can set the locale to your language and use locale.strcoll to compare strings using your language's sorting rules.
Use the key argument instead. It takes a function that takes the value being processed and returns a single value giving the key to use to sort by.
sorted(x, key=somekeyfunc)

Python TypeError: non-empty format string passed to object.__format__ on example 24 from learn python the hard way book [duplicate]

Suppose I have a function like:
def myfun(a, b, c):
return (a * 2, b + c, c + b)
Given a tuple some_tuple = (1, "foo", "bar"), how can I use some_tuple to call myfun, to get the result (2, "foobar", "barfoo")
I know could define myfun so that it accepts the tuple directly, but I want to call the existing myfun.
See also: What do the * (star) and ** (double star) operators mean in a function call?.
myfun(*some_tuple) does exactly what you request. The * operator simply unpacks the tuple (or any iterable) and passes them as the positional arguments to the function. Read more about unpacking arguments.
Note that you can also expand part of argument list:
myfun(1, *("foo", "bar"))
Take a look at the Python tutorial section 4.7.3 and 4.7.4.
It talks about passing tuples as arguments.
I would also consider using named parameters (and passing a dictionary) instead of using a tuple and passing a sequence. I find the use of positional arguments to be a bad practice when the positions are not intuitive or there are multiple parameters.
This is the functional programming method. It lifts the tuple expansion feature out of syntax sugar:
apply_tuple = lambda f, t: f(*t)
Redefine apply_tuple via curry to save a lot of partial calls in the long run:
from toolz import curry
apply_tuple = curry(apply_tuple)
Example usage:
from operator import add, eq
from toolz import thread_last
thread_last(
[(1,2), (3,4)],
(map, apply_tuple(add)),
list,
(eq, [3, 7])
)
# Prints 'True'
Similar to #Dominykas's answer, this is a decorator that converts multiargument-accepting functions into tuple-accepting functions:
apply_tuple = lambda f: lambda args: f(*args)
Example 1:
def add(a, b):
return a + b
three = apply_tuple(add)((1, 2))
Example 2:
#apply_tuple
def add(a, b):
return a + b
three = add((1, 2))

what is the signification of ** in python (when not a mathematical expression) [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 9 years ago.
here is a small portion of code
import networkx as nx
G=nx.MultiDiGraph()
...
G.add_edge(white, black, **game)
(game is a dictionnary)
what is the role of ** in the last line
** is the operator which unpacks mapping types (e.g. a dict) into keyword arguments.
Consider:
def foo(bar=1):
print bar
d = {'bar':2}
foo(**d)
In this example, 2 will be printed. On the other side, you can also absorb all unknown keyword arguments in a **kwargs type variable:
def foo(a=1,b=2,**kwargs):
print kwargs
foo(a=1,b=2,c=3)
Of course, you can combine these forms as well:
def foo(a=1,b=2,**kwargs):
print b
print kwargs
d = {'b':3, 'c':4}
foo(**d)
The function add_edge gets passed in the dictionary game as keyword arguments. For example, the following two are equivalent:
game = {'weight': 5, 'color': 'blue'}
G.add_edge(white, black, **game)
G.add_edge(white, black, weight=5, color='blue')
It expands a dictionary so its key-pair values are used as named parameters. Consider, for example, this function:
>>> def f(a, b, c):
... return a+b-c
...
I can call it passing its arguments in the original order:
>>> f(1,2,3)
0
But I can also switch them if I attribute values to the argument names:
>>> f(1,c=3,b=2)
0
When one calls a function passing a dictionary preceded by **, the pairs of this dictionary will be used as parameters. So, I could create the dictionary below
>>> params = {'c':3, 'b':2}
...and pass it to my function...
>>> f(1,**params)
0
...and will get the same result.
It means that the argument is a dictionary, basically.
It's usually used as **kwargs, meaning, keyword arguments.
For instance, when you define a method like:
def myMethod(first, *args, **kwargs):
....
It means that the second argument is expected to be a collection (a "list" of arguments), and kwargs is meant to be a dict.

Passing functions which have multiple return values as arguments in Python

So, Python functions can return multiple values. It struck me that it would be convenient (though a bit less readable) if the following were possible.
a = [[1,2],[3,4]]
def cord():
return 1, 1
def printa(y,x):
print a[y][x]
printa(cord())
...but it's not. I'm aware that you can do the same thing by dumping both return values into temporary variables, but it doesn't seem as elegant. I could also rewrite the last line as "printa(cord()[0], cord()[1])", but that would execute cord() twice.
Is there an elegant, efficient way to do this? Or should I just see that quote about premature optimization and forget about this?
printa(*cord())
The * here is an argument expansion operator... well I forget what it's technically called, but in this context it takes a list or tuple and expands it out so the function sees each list/tuple element as a separate argument.
It's basically the reverse of the * you might use to capture all non-keyword arguments in a function definition:
def fn(*args):
# args is now a tuple of the non-keyworded arguments
print args
fn(1, 2, 3, 4, 5)
prints (1, 2, 3, 4, 5)
fn(*[1, 2, 3, 4, 5])
does the same.
Try this:
>>> def cord():
... return (1, 1)
...
>>> def printa(y, x):
... print a[y][x]
...
>>> a=[[1,2],[3,4]]
>>> printa(*cord())
4
The star basically says "use the elements of this collection as positional arguments." You can do the same with a dict for keyword arguments using two stars:
>>> a = {'a' : 2, 'b' : 3}
>>> def foo(a, b):
... print a, b
...
>>> foo(**a)
2 3
Actually, Python doesn't really return multiple values, it returns one value which can be multiple values packed into a tuple. Which means that you need to "unpack" the returned value in order to have multiples.
A statement like
x,y = cord()
does that, but directly using the return value as you did in
printa(cord())
doesn't, that's why you need to use the asterisk. Perhaps a nice term for it might be "implicit tuple unpacking" or "tuple unpacking without assignment".

Categories