Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Unpacking zip object
#1
Here's some code:

exceptions = 0

a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']

try:
    xp, yp, m = zip(a,b,c)
except:
    output = zip(a, b, c)
    exceptions +=1

for xp, yp, m in output:
    print(xp, yp, m)
    
print(f'Number of exceptions is {exceptions}.')
Why do I need the for loop to unpack this? Without it, the ValueError is "too many items to unpack" and I don't fully understand how that arises.

From the try block, I would expect to see a list of tuples.
Reply
#2
Zip returns an iterator. You can loop over that iterator to get the elements, or you can assign all the elements.

But since you hand your zip iterables that all have 4 elements, your zip iterator will also have 4 elements.
This means if you try to assign it to (xp, yp, m), it will complain that 4 elements can't fit into 3 variables. I can't tell from your program if you mean for xp to have the first "set" from the zip or if you expected it to have the "a" portion.

zip([1,2,3,4], [5,6,7,8]) => (1,5), (2,6), (3,7), (4,8) # 4 elements.

Describe more what you want those variables to contain, but looping over a zip is pretty natural.
Mark17 likes this post
Reply
#3
Hello,
Sorry
I speak Python but I don't speak English (I just read it a little). If I express myself badly, please blame the translator^^.
Reply
#4
(Mar-24-2022, 07:41 PM)bowlofred Wrote: Zip returns an iterator. You can loop over that iterator to get the elements, or you can assign all the elements.

But since you hand your zip iterables that all have 4 elements, your zip iterator will also have 4 elements.
This means if you try to assign it to (xp, yp, m), it will complain that 4 elements can't fit into 3 variables. I can't tell from your program if you mean for xp to have the first "set" from the zip or if you expected it to have the "a" portion.

zip([1,2,3,4], [5,6,7,8]) => (1,5), (2,6), (3,7), (4,8) # 4 elements.

Describe more what you want those variables to contain, but looping over a zip is pretty natural.

I'm still confused.

My thinking was that this would unpack the lists one element at a time and put the a component in xp, the b component in yp, and the c component in m. There would be 4 groupings of 3 elements, but I thought number of groupings would be inconsequential as any could be accommodated. What would be problematic would be trying to unpack 4 variables to 3 or 5 to 3 or any unequal number. I have three (a, b, c) being unpacked to three (xp, yp, m).
Reply
#5
(Mar-24-2022, 09:32 PM)Mark17 Wrote: I have three (a, b, c) being unpacked to three (xp, yp, m).

But you don't have 3 elements in a,b,c, you have a total of 12. You can't put them into 3 variables with a single assignment. You could do that if you loop over them and change it each time.

Is this what you intend?

a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']


for xp, yp, m in zip(a, b, c):
    print(f"This time through the loop {xp=}, {yp=}, {m=}")
Output:
This time through the loop xp='1-6-2017', yp=265, m='d' This time through the loop xp='1-13-2017', yp=-10, m='' This time through the loop xp='1-20-2017', yp=130, m='d' This time through the loop xp='1-27-2017', yp=330, m=''
Mark17 likes this post
Reply
#6
(Mar-24-2022, 10:09 PM)bowlofred Wrote:
(Mar-24-2022, 09:32 PM)Mark17 Wrote: I have three (a, b, c) being unpacked to three (xp, yp, m).

But you don't have 3 elements in a,b,c, you have a total of 12. You can't put them into 3 variables with a single assignment. You could do that if you loop over them and change it each time.

Is this what you intend?

a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']


for xp, yp, m in zip(a, b, c):
    print(f"This time through the loop {xp=}, {yp=}, {m=}")
Output:
This time through the loop xp='1-6-2017', yp=265, m='d' This time through the loop xp='1-13-2017', yp=-10, m='' This time through the loop xp='1-20-2017', yp=130, m='d' This time through the loop xp='1-27-2017', yp=330, m=''

Ah ha!! That's what I did not understand. It's all clear now. Thanks!
Reply
#7
I can't tell if this is a confusion about iterators or a confusion about unpacking question.

As bowlofred said, zip returns an iterator. You give it an iterable. It returns an iterator. Each time you call next(iterator) you get the next item in the iterable.
a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
x = zip(a)
print(next(x), next(x))
Output:
('1-6-2017',) ('1-13-2017',)
Notice that zip returns tuples. This is because zip expects you to provide multiple iterables.
a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']
x = zip(a, b, c)
print(next(x), next(x))
Output:
('1-6-2017', 265, 'd') ('1-13-2017', -10, '')
If you pass zip 1 iterable, each tuple contains 1 value. If you pass zip 3 iterables, each tuple contains 3 values.

Since zip is an iterator, it will return all the values one at a time and then raise a StopIteration exception.
a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']
x = zip(a, b, c)
print(next(x), next(x), next(x), next(x), next(x))
Error:
Traceback (most recent call last): File "...", line 5, in <module> print(next(x), next(x), next(x), next(x), next(x)) StopIteration
Normally you don't have to worry about the StopIteration exception because you use zip() in a for loop, and "for" processes the exception as the end of loop condition.

a, b, and c each have 4 items, so zip(a, b, c) can be iterated 4 times before raising the StopIteration exception.

Python supports packing and unpacking sequences. An iterator is a sequence, so you can unpack an iterator.
a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']
x, y, *z = zip(a, b, c)
print(x, y, z)
Output:
('1-6-2017', 265, 'd') ('1-13-2017', -10, '') [('1-20-2017', 130, 'd'), ('1-27-2017', 330, '')]
I told Python that z will take all remaining values from the iterator, and when printing you can see that z contains two values, not one. This makes sense. a, b and c each are each len 4. zip(a, b, c) will produce 4 values before raising the StopIteration exception. Unpacking puts the first item in x, the second in y, and the two remaining items in z. There are 4 items to unpack. 4 items cannot be unpacked into 3 variables (well, they can, but you know what I mean).

When I first read you post I thought you were trying to transpose this group of lists:
Quote:a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']
Into somethin like this:
Quote:[('1-6-2017', 265, 'd'), ('1-13-2017', -10, ''), ('1-20-2017', 130, 'd'), ('1-27-2017', 330, '')]
The Python for doing that is:
x = list(zip(a, b, c))
And I could then iterate over the tuples in x.
for xp, yp, m in x:
    print(xp, yp, m)
Output:
1-6-2017 265 d 1-13-2017 -10 1-20-2017 130 d 1-27-2017 330
Now I am unpacking tuples, not an iterator. Each tuple is len 3, so I need 3 variables to unpack.
Reply
#8
(Mar-25-2022, 07:27 PM)deanhystad Wrote: I can't tell if this is a confusion about iterators or a confusion about unpacking question.

As bowlofred said, zip returns an iterator. You give it an iterable. It returns an iterator. Each time you call next(iterator) you get the next item in the iterable.
...
Python supports packing and unpacking sequences.  An iterator is a sequence, so you can unpack an iterator.
[python]a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']
x, y, *z = zip(a, b, c)
print(x, y, z)
Output:
('1-6-2017', 265, 'd') ('1-13-2017', -10, '') [('1-20-2017', 130, 'd'), ('1-27-2017', 330, '')]
I told Python that z will take all remaining values from the iterator, and when printing you can see that z contains two values, not one. This makes sense. a, b and c each are each len 4. zip(a, b, c) will produce 4 values before raising the StopIteration exception. Unpacking puts the first item in x, the second in y, and the two remaining items in z. There are 4 items to unpack. 4 items cannot be unpacked into 3 variables (well, they can, but you know what I mean).

...

What I took from bowlofred was the "too many items to unpack" Traceback referred to a total of 12 items trying to be unpacked into 3 variables. What you're saying here, though, is that it's about four sets being unpacked into three variables. I have misunderstood on this point. I have expected values from a to go in xp, values from b to go in yp, and values from c to go in m. I now believe it's the first grouping of x, y, z going into xp, the second grouping of x, y, z going into yp, and the remaining (with the * operator) groupings going into m. I'll have to go back to bowlofred's comments and see how they compare to the example you gave.

The question here that pertains most to my current application is why does the first ax.plot() output a line while the second ax.plot outputs a set of markers (or lack thereof if I indicate None):

a = ['1-6-2017', '1-13-2017', '1-20-2017', '1-27-2017']
b = [265, -10, 130, 330]
c = ['d', '', 'd', '']

fig, ax = plt.subplots(1)

ax.plot(a,b) #This plots line.
plt.xticks(rotation=90) 
for xp, yp, m in zip(a, b, c): #need for-loop (else "too many values to unpack")
    ax.plot(xp,yp,m,color='orange',markersize=12) #this plots markers
plt.tight_layout() #this doesn't seem to do anything?
plt.show()
I'm going to take a guess. ax.plot() is a method that plots line graphs. However, if you present just one value at a time, then it's only going to plot the point. The second line is a loop that revisits ax.plot() several times but each time, presents only one set of values to it.
Reply
#9
Matplotlib draws lines between points. If you give it 100 points it will draw 99 lines. If you give it two points it will draw 1 line. If you give it one point it doesn't draw a line.

Try passing some arguments to tight_layout. The effects can be subtle. It is more noticeable if you have multiple subplots.
Mark17 likes this post
Reply
#10
What you were missing is the intermediate step int he packing/unpacking.
zip(a, b, c) produces this series:
('1-6-2017', 265, 'd'), ('1-13-2017', -10, ''), ('1-20-2017', 130, 'd'), ('1-27-2017', 330, '')
or
(a0, b0, c0), (a1, b1, c1), (a2, b2, c2), (a3, b3, c3)

When you do xp, yp, m = zip(a, b, c) it tries to unpack that series of 4 into 3 variables. 4 does not fit into 3, so you get an error.

When you do "for xp, yp, m in zip(a, b, c): you are unpacking the tuple (ax, bx, cx) into xp, yp and m.
Mark17 likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Unpacking a dict with * or ** msrk 4 918 Dec-02-2023, 11:50 PM
Last Post: msrk
  iterate through the dict_values while unpacking the dictionary PeacockOpenminded 3 1,262 Jan-22-2023, 12:44 PM
Last Post: PeacockOpenminded
  unpacking list wardancer84 2 1,837 Sep-11-2021, 02:42 PM
Last Post: wardancer84
  unpacking tuple not working project_science 1 1,451 Jan-09-2021, 09:09 PM
Last Post: buran
  Unpacking a list Mark17 3 2,555 Dec-18-2020, 05:08 AM
Last Post: aajkaal
  Unpacking wheel files DavidTheGrockle 3 10,885 Dec-15-2020, 05:11 PM
Last Post: DavidTheGrockle
  Why the result of "extended iterable unpacking" with set() is unpredictable? zohanlin 2 2,016 Jun-29-2020, 10:30 AM
Last Post: zohanlin
  Unpacking nested lists yonatan776 1 2,160 Apr-14-2020, 08:50 PM
Last Post: buran
  Unpacking dictionary from .xlsx as Kwargs etjkai 5 2,793 Dec-27-2019, 05:31 PM
Last Post: etjkai
  Tuple Unpacking HarshaliPatel 3 2,783 Jan-30-2019, 12:42 PM
Last Post: dukoolsharma

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020