Why arguments to dictionary[] are interpreted as a single key? [duplicate] - python

This question already has answers here:
When are parentheses required around a tuple?
(3 answers)
Closed 6 years ago.
If I declare a dictionary like:
a = {(1, 2, 3): 10, (4, 5, 6):20}
the I can reference the elements as using the keys as:
a[(1, 2, 3)]
why this:
a[1, 2, 3]
results in the same operation? If is were a function it should raise an error since I am passing three parameters instead of one.

a[1, 2, 3]
It takes as a tuple.
>>>a = 1,2,3
>>>type(a)
tuple

1, 2, 3 is a tuple, just like (1, 2, 3). Tuples are defined by the commas. The parentheses are for grouping in cases that might otherwise be ambiguous.

You're still passing in a tuple, just using other syntax.
(a, b, c, d) is the same as a, b, c, d, they both construct a tuple.

Because declaring x,y,z is a implicit way of declaring a tuple. Try this:
>>> n = 1,2
>>> n
(1, 2)

Related

What is returned after using *[] [duplicate]

This question already has answers here:
What do the * (star) and ** (double star) operators mean in a function call?
(4 answers)
Closed 2 years ago.
I'm using itertools.chain to "flatten" a list of lists in this fashion:
uniqueCrossTabs = list(itertools.chain(*uniqueCrossTabs))
how is this different than saying:
uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))
* is the "splat" operator: It takes an iterable like a list as input, and expands it into actual positional arguments in the function call.
So if uniqueCrossTabs were [[1, 2], [3, 4]], then itertools.chain(*uniqueCrossTabs) is the same as saying itertools.chain([1, 2], [3, 4])
This is obviously different from passing in just uniqueCrossTabs. In your case, you have a list of lists that you wish to flatten; what itertools.chain() does is return an iterator over the concatenation of all the positional arguments you pass to it, where each positional argument is iterable in its own right.
In other words, you want to pass each list in uniqueCrossTabs as an argument to chain(), which will chain them together, but you don't have the lists in separate variables, so you use the * operator to expand the list of lists into several list arguments.
chain.from_iterable() is better-suited for this operation, as it assumes a single iterable of iterables to begin with. Your code then becomes simply:
uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))
It splits the sequence into separate arguments for the function call.
>>> def foo(a, b=None, c=None):
... print a, b, c
...
>>> foo([1, 2, 3])
[1, 2, 3] None None
>>> foo(*[1, 2, 3])
1 2 3
>>> def bar(*a):
... print a
...
>>> bar([1, 2, 3])
([1, 2, 3],)
>>> bar(*[1, 2, 3])
(1, 2, 3)
Just an alternative way of explaining the concept/using it.
import random
def arbitrary():
return [x for x in range(1, random.randint(3,10))]
a, b, *rest = arbitrary()
# a = 1
# b = 2
# rest = [3,4,5]

What does * mean in front of self.dictionary.values() in a class in Python? [duplicate]

This question already has answers here:
What do the * (star) and ** (double star) operators mean in a function call?
(4 answers)
Closed 2 years ago.
I'm using itertools.chain to "flatten" a list of lists in this fashion:
uniqueCrossTabs = list(itertools.chain(*uniqueCrossTabs))
how is this different than saying:
uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))
* is the "splat" operator: It takes an iterable like a list as input, and expands it into actual positional arguments in the function call.
So if uniqueCrossTabs were [[1, 2], [3, 4]], then itertools.chain(*uniqueCrossTabs) is the same as saying itertools.chain([1, 2], [3, 4])
This is obviously different from passing in just uniqueCrossTabs. In your case, you have a list of lists that you wish to flatten; what itertools.chain() does is return an iterator over the concatenation of all the positional arguments you pass to it, where each positional argument is iterable in its own right.
In other words, you want to pass each list in uniqueCrossTabs as an argument to chain(), which will chain them together, but you don't have the lists in separate variables, so you use the * operator to expand the list of lists into several list arguments.
chain.from_iterable() is better-suited for this operation, as it assumes a single iterable of iterables to begin with. Your code then becomes simply:
uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))
It splits the sequence into separate arguments for the function call.
>>> def foo(a, b=None, c=None):
... print a, b, c
...
>>> foo([1, 2, 3])
[1, 2, 3] None None
>>> foo(*[1, 2, 3])
1 2 3
>>> def bar(*a):
... print a
...
>>> bar([1, 2, 3])
([1, 2, 3],)
>>> bar(*[1, 2, 3])
(1, 2, 3)
Just an alternative way of explaining the concept/using it.
import random
def arbitrary():
return [x for x in range(1, random.randint(3,10))]
a, b, *rest = arbitrary()
# a = 1
# b = 2
# rest = [3,4,5]

What does * mean in python function? [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 2 years ago.
Here is one easy math function in Jupyter using Python 3
def sum(*formulation):
ans = 0
for i in formulation:
ans += i
return ans
If I want to try this function, I write down like this:
sum(1,2,3,4)
The output will be
10
My question is what is * mean in sum(*formulation)?
Because if I don't use *, I get an error.
The "*" and then "**" notation are called "packing" and "unpacking". The main idea is that if you unpack objects, the they are removed from their list/dict and if you pack objects, then they are placed into a list/dict. For example,
x = [*[1,2,3],4]
print(x)
Here I have "unpacked" the [1,2,3] into the list for "x". Hence, x is now [1,2,3,4]. Here is another example,
d1 = {'x':7}
d2 = {'y':10}
d3 = {**d1,**d2}
Here I have dictionary "unpacked" the first two dictionaries into the third one. Here is another example:
def func(*args):
print(args)
func(1,2,3,4,5)
Here the 1,2,3,4,5 are not in a list, hence they will be "packed" into a list called args in the func.
That is called a starred expression. In the argument list of a function, this means that all other supplied positional arguments (that are not caught by preceding positional arguments) will be "packed" into the starred variable as a list.
So
def function(*arguments):
print(arguments)
function(1, 2, 3)
will return
[1, 2, 3]
Note that it has different behaviour in other contexts in which it is usually used to "unpack" lists or other iterables. The Searchwords for that would be "starred", "packing" and "unpacking".
A good mnemonic for unpacking is that they remove the list brackets
a, b, c = *[1, 2, 3] #equivalent to
a, b, c = 1, 2, 3
And for packing like a regex wildcard
def function(*arguments):
pass
def function(zero, or_, more, arguments):
pass
head, *everything_in_between, tail = [1, 2, 3, 4, 5, 6]
It means that the function takes zero or more arguments and the passed arguments would be collected in a list called formulation.
For example, when you call sum(1, 2, 3, 4), formation would end up being [1, 2, 3, 4].
Another similar but different usage of * that you might come across is when calling the function. Say you have a function defined as def add(a, b), and you have a list l = [1, 2], when you call add(*l) it means to unpack l and is equivalent to add(l[0], l[1]).

Multiple assignment semantics

In Python one can do:
a, b = 1, 2
(a, b) = 1, 2
[a, b] = 1, 2
I checked the generated bytecode using dis and they are identical.
So why allow this at all? Would I ever need one of these instead of the others?
One case when you need to include more structure on the left hand side of the assignment is when you're asking Python unpack a slightly more complicated sequence. E.g.:
# Works
>>> a, (b, c) = [1, [2, 3]]
# Does not work
>>> a, b, c = [1, [2, 3]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 2 values to unpack
This has proved useful for me in the past, for example, when using enumerate to iterate over a sequence of 2-tuples. Something like:
>>> d = { 'a': 'x', 'b': 'y', 'c': 'z' }
>>> for i, (key, value) in enumerate(d.iteritems()):
... print (i, key, value)
(0, 'a', 'x')
(1, 'c', 'z')
(2, 'b', 'y')
Python tuples can often be written with or without the parentheses:
a = 1, 2, 3
is equivalent to
a = (1, 2, 3)
In some cases, you need parentheses to resolve ambiguities, for examples if you want to pass the tuple (1, 2) to the function f, you will have to write f((1, 2)). Because the parentheses are sometimes needed, they are always allowed for consistency, just like you can always write (a + b) instead of a + b.
If you want to unpack a nested sequence, you also need parentheses:
a, (b, c) = 1, (2, 3)
There does not seem to be a reason to also allow square brackets, and people rarely do.
When unpacking a single-element iterable, the list syntax is prettier:
a,=f() # comma looks out of place
(a,)=f() # still odd
[a]=f() # looks like every other list
They are also same because the assignment happens from Right to left and on the right, you have one type, which is a sequence of two elements. When the asignment call is made, the sequence is unpacked and looked for corresponding elements to match and given to those values.
Yes, any one way should be fine in this case where the sequence is unpacked to respective elements.
An open parenthesis allows for a multi-line assignment. For example, when reading a row from csv.reader(), it makes code more readable (if less efficient) to load the list into named variables with a single assignment.
Starting with a parenthesis avoids long or \ escaped lines.
(a, b,
c) = [1, 2, 3]
(Imagine more and longer variable names)

How to zip lists in a list [duplicate]

This question already has answers here:
Expanding tuples into arguments
(5 answers)
Closed 6 months ago.
I want to zip the following list of lists:
>>> zip([[1,2], [3,4], [5,6]])
[[1,3,5], [2,4,6]]
This could be achieved with the current zip implementation only if the list is split into individual components:
>>> zip([1,2], [3,4], [5,6])
(1, 3, 5), (2, 4, 6)]
Can't figure out how to split the list and pass the individual elements to zip. A functional solution is preferred.
Try this:
>>> zip(*[[1,2], [3,4], [5,6]])
[(1, 3, 5), (2, 4, 6)]
See Unpacking Argument Lists:
The reverse situation occurs when the arguments are already in a list or tuple but need to be unpacked for a function call requiring separate positional arguments. For instance, the built-in range() function expects separate start and stop arguments. If they are not available separately, write the function call with the *-operator to unpack the arguments out of a list or tuple:
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]

Categories