1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
# Tests for extended unpacking, starred expressions.
doctests = """
Unpack tuple
>>> t = (1, 2, 3)
>>> a, *b, c = t
>>> a == 1 and b == [2] and c == 3
True
Unpack list
>>> l = [4, 5, 6]
>>> a, *b = l
>>> a == 4 and b == [5, 6]
True
Unpack implied tuple
>>> *a, = 7, 8, 9
>>> a == [7, 8, 9]
True
Unpack string... fun!
>>> a, *b = 'one'
>>> a == 'o' and b == ['n', 'e']
True
Unpack long sequence
>>> a, b, c, *d, e, f, g = range(10)
>>> (a, b, c, d, e, f, g) == (0, 1, 2, [3, 4, 5, 6], 7, 8, 9)
True
Unpack short sequence
>>> a, *b, c = (1, 2)
>>> a == 1 and c == 2 and b == []
True
Unpack generic sequence
>>> class Seq:
... def __getitem__(self, i):
... if i >= 0 and i < 3: return i
... raise IndexError
...
>>> a, *b = Seq()
>>> a == 0 and b == [1, 2]
True
Unpack in for statement
>>> for a, *b, c in [(1,2,3), (4,5,6,7)]:
... print(a, b, c)
...
1 [2] 3
4 [5, 6] 7
Unpack in list
>>> [a, *b, c] = range(5)
>>> a == 0 and b == [1, 2, 3] and c == 4
True
Multiple targets
>>> a, *b, c = *d, e = range(5)
>>> a == 0 and b == [1, 2, 3] and c == 4 and d == [0, 1, 2, 3] and e == 4
True
Now for some failures
Unpacking non-sequence
>>> a, *b = 7
Traceback (most recent call last):
...
TypeError: 'int' object is not iterable
Unpacking sequence too short
>>> a, *b, c, d, e = Seq()
Traceback (most recent call last):
...
ValueError: need more than 3 values to unpack
Unpacking a sequence where the test for too long raises a different kind of
error
>>> class BozoError(Exception):
... pass
...
>>> class BadSeq:
... def __getitem__(self, i):
... if i >= 0 and i < 3:
... return i
... elif i == 3:
... raise BozoError
... else:
... raise IndexError
...
Trigger code while not expecting an IndexError (unpack sequence too long, wrong
error)
>>> a, *b, c, d, e = BadSeq()
Traceback (most recent call last):
...
test.test_unpack_ex.BozoError
Now some general starred expressions (all fail).
>>> a, *b, c, *d, e = range(10) # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: two starred expressions in assignment (...)
>>> [*b, *c] = range(10) # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: two starred expressions in assignment (...)
>>> *a = range(10) # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: starred assignment target must be in a list or tuple (...)
>>> *a # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: can use starred expression only as assignment target (...)
>>> *1 # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: can use starred expression only as assignment target (...)
>>> x = *a # doctest:+ELLIPSIS
Traceback (most recent call last):
...
SyntaxError: can use starred expression only as assignment target (...)
"""
__test__ = {'doctests' : doctests}
def test_main(verbose=False):
import sys
from test import test_support
from test import test_unpack_ex
test_support.run_doctest(test_unpack_ex, verbose)
if __name__ == "__main__":
test_main(verbose=True)
|