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)
Related
I am working on a project where I got some data back in the form of a tuple, since a lot of it wasn't really needed I unpacked it and took what I needed, I need to make a new tuple with it how can I pack it back to original state within the tuple again ?
example code is :
name,*unused,amount=(name,age,address,email,contact,amount)
#this is how data gets unpacked
name=name
amount=amount
unused=['age','address','email','contact']
when I try packing it again using the tuple itself it becomes
data=(name,['age','address','email','contact'],amount)
is there any way to pack it back as the original state, as of now I'm manually unpacking the list and making the tuple again and want to avoid use of this extra function, looking for an internal way of doing it .
If I understand your question correctly, you are looking for this?. You can use * operator to unpack the the list elements
>>> first, *middle, last = (1, 2, 3, 4, 5)
>>> first
1
>>> middle
[2, 3, 4]
>>> last
5
>>> (first, *middle, last)
(1, 2, 3, 4, 5)
Python3's range objects support O(1) containment checking for integers (1) (2)
So one can do 15 in range(3, 19, 2) and get the correct answer True
However, it doesn't support containment checking b/w two ranges
a = range(0, 10)
b = range(3, 7)
a in b # False
b in a # False, even though every element in b is also in a
a < b # TypeError: '<' not supported between instances of 'range' and 'range'
It seems that b in a is interpreted as is any element in the range 'a' equal to the object 'b'?
However, since the range cannot contain anything but integers, range(...) in range(...) will always return False. IMHO, such a query should be answered as is every element in range 'b' also in range 'a'? Given that range only stores the start, stop, step and length, this query can also be answered in O(1).
The slice object doesn't help either. It doesn't implement the __contains__ method, and the __lt__ method simply compares two slices as tuples (which makes no sense)
Is there a reason behind the current implementation of these, or is it just a "it happened to be implemented this way" thing?
It looks like the implementation of __contains__ for ranges is range_contains, which just checks if the given element is in the iterable, with a special case for longs.
As you have correctly observed, e in b returns true iff e is an element in b. Any other implementation, such as one that checks if e is a subset of b, would be ambiguous. This is especially problematic in Python, which doesn't require iterables be homogenous, and allows nested lists/tuples/sets/iterables.
Consider a world where your desired behavior was implemented. Now, suppose we have the following list:
my_list = [1, 2, (3, 4), 5]
ele1 = (3, 4)
ele2 = (2, 5)
In this case, what should ele1 in my_list and ele2 in my_list return? Your desired behavior makes it tedious to write code such as
if e in my_iterable:
# ah! e must exist!
my_iterable.remove(e)
A safer, better way is to keep the current behavior, and instead use a different type-sensitive operator to implement subset predicates:
x = set([1])
y = set([1,2])
x < y # True
[1] < y # raises a TypeError
You're confusing 'b' containing 'a' with 'a' being a subset of 'b' - These are two different things.
b containing a means range(0, 10) is inside b. Let's say:
a = [1, 2, 3]
and
b = [1, 2, 3, 4, 5]
a in b is only true if the actual list [1, 2, 3] is in [[1, 2, 3], 4, 5]. So you're actually checking if the list itself is inside the other list, not that all the elements are in the other list.
A list a is a subset of b if all elements of a are inside b. In your example, b is a subset of a, yes, but the actual list b is not IN a.
If you want to do such methods, then it's probably recommended that you use a set data structure
Range objects implement the collections.abc.Sequence, It supports containment tests.
a in b
b in a
In this case, you are searching for Range object a in range b, vice versa. It should be false.
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)
I'm trying to do something like this in python:
def f():
b = ['c', 8]
return 1, 2, b*, 3
Where I want f to return the tuple (1, 2, 'c', 8, 3). I found a way to do this using itertools followed by tuple, but this is not very nice, and I was wondering whether there exists an elegant way to do this.
The unpacking operator * appears before the b, not after it.
return (1, 2, *b, 3)
# ^ ^^ ^
However, this will only work on Python 3.5+ (PEP 448), and also you need to add parenthesis to prevent SyntaxError. In the older versions, use + to concatenate the tuples:
return (1, 2) + tuple(b) + (3,)
You don't need the tuple call if b is already a tuple instead of a list:
def f():
b = ('c', 8)
return (1, 2) + b + (3,)
Note the accepted answer explains how to unpack some values when returning them as part of a tuple that includes some other values. What if you only want to return the unpacked list? Following up on a comment above:
def func():
list1 = [1,2,3]
return *list1
This gives SyntaxError: invalid syntax.
The solution is to add parentheses ( and ) and a comma , after the return value, to tell Python that this unpacked list is part of a tuple:
def func():
list1 = [1,2,3]
return (*list1,)
Sometime I write code like this:
a,temp,b = s.partition('-')
I just need to pick the first and 3rd elements. temp would never be used. Is there a better way to do this?
In other terms, is there a better way to pick distinct elements to make a new list?
For example, I want to make a new list using the elements 0,1,3,7 from the old list. The
code would be like this:
newlist = [oldlist[0],oldlist[1],oldlist[3],oldlist[7]]
It's pretty ugly, isn't it?
Be careful using
a, _, b = s.partition('-')
sometimes _ is use for internationalization (gettext), so you wouldn't want to accidentally overwrite it.
Usually I would do this for partition rather than creating a variable I don't need
a, b = s.partition('-')[::2]
and this in the general case
from operator import itemgetter
ig0137 = itemgetter(0, 1, 3, 7)
newlist = ig0137(oldlist)
The itemgetter is more efficient than a list comprehension if you are using it in a loop
For the first there's also this alternative:
a, b = s.partition('-')[::2]
For the latter, since there's no clear interval there is no way to do it too clean. But this might suit your needs:
newlist = [oldlist[k] for k in (0, 1, 3, 7)]
You can use Python's extended slicing feature to access a list periodically:
>>> a = range(10)
>>> # Pick every other element in a starting from a[1]
>>> b = a[1::2]
>>> print b
>>> [1, 3, 5, 7, 9]
Negative indexing works as you'd expect:
>>> c = a[-1::-2]
>>> print c
>>> [9, 7, 5, 3, 1]
For your case,
>>> a, b = s.partition('-')[::2]
the common practice in Python to pick 1st and 3rd values is:
a, _, b = s.partition('-')
And to pick specified elements in a list you can do :
newlist = [oldlist[k] for k in (0, 1, 3, 7)]
If you don't need to retain the middle field you can use split (and similarly rsplit) with the optional maxsplit parameter to limit the splits to the first (or last) match of the separator:
a, b = s.split('-', 1)
This avoids a throwaway temporary or additional slicing.
The only caveat is that with split, unlike partition, the original string is returned if the separator is not found. The attempt to unpack will fail as a result. The partition method always returns a 3-tuple.