Velocity Reviews > list mutability

# list mutability

gigs
Guest
Posts: n/a

 02-18-2008
hi im having this code

l = [1, 3, 5, 'D', 1, 2, 3, 4, 5, 6, 7, 'A', 'S', 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 'A']

why i need to copy x list? can someone explain me. If i dont copy it i get this
result:
>>> took_num_range(l)

[[1, 2, 3, 4, 5, 6, 7], [6, 5, 4, 3, 2, 1, 0], [6, 5, 4, 3, 2, 1, 0], [6, 5, 4,
3, 2, 1, 0], [6, 5, 4, 3, 2, 1, 0]]

but if i copy it i get result as im looking for
>>> took_num_range(l)

[[1, 2, 3, 4, 5, 6, 7], [9, 8, 7, 6, 5, 4, 3], [8, 7, 6, 5, 4, 3, 2], [7, 6, 5,
4, 3, 2, 1], [6, 5, 4, 3, 2, 1, 0]]
>>>

def took_num_range(l):
j = []
x = []
for i in l:
if type(i) is int and len(x) == 7:
j.append(x)
x = x[:] # im mean here
x.pop(0)
if type(i) is int and len(x) < 7:
x.append(i)
if type(i) is not int and len(x) == 7:
j.append(x)
x = []
if type(i) is not int and len(x) != 7:
x = []
return j

thx

John Machin
Guest
Posts: n/a

 02-18-2008
On Feb 19, 5:09 am, gigs <(E-Mail Removed)-com.hr> wrote:
> hi im having this code
>
> l = [1, 3, 5, 'D', 1, 2, 3, 4, 5, 6, 7, 'A', 'S', 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 'A']
>
> why i need to copy x list? can someone explain me. If i dont copy it i get this
> result:
> >>> took_num_range(l)

> [[1, 2, 3, 4, 5, 6, 7], [6, 5, 4, 3, 2, 1, 0], [6, 5, 4, 3, 2, 1, 0], [6, 5, 4,
> 3, 2, 1, 0], [6, 5, 4, 3, 2, 1, 0]]
>
> but if i copy it i get result as im looking for
> >>> took_num_range(l)

> [[1, 2, 3, 4, 5, 6, 7], [9, 8, 7, 6, 5, 4, 3], [8, 7, 6, 5, 4, 3, 2], [7, 6, 5,
> 4, 3, 2, 1], [6, 5, 4, 3, 2, 1, 0]]
> >>>

>
> def took_num_range(l):
> j = []
> x = []
> for i in l:
> if type(i) is int and len(x) == 7:
> j.append(x)
> x = x[:] # im mean here
> x.pop(0)

j.append(x) saves a reference to the same list that x refers to. So
when you later mutate that one list, all references in j refer to the
mutated list.

x = x[:]
x.pop(0)
which copies the contents twice, you can do
x = x[1:]

In a more complicated example, it would be better to take a copy at
each point:

j.append(x[:])

.... then you are sure you have a photo of x and it doesn't matter how/
when you mutate x later.

> if type(i) is int and len(x) < 7:

This is a big trap for the casual reader (len(x) may have changed
since the previous "if" statement) ... see below.

> x.append(i)
> if type(i) is not int and len(x) == 7:
> j.append(x)
> x = []
> if type(i) is not int and len(x) != 7:
> x = []

What do you want to do if your input ends with 7 integers and no
letter, e.g.
[1,2,3,'A',1,2,3,4,5,6,7]
?

> return j

Some suggestions:
1. use meaningful names
2. don't have hard-wired numbers like 7
3. use "else" and "elif" as appropriate to avoid repeating conditions
unnecessarily.

Here's a suggested replacement for your code, tested to the extent
shown:

C:\junk>type tooknumrange.py
def took_num_range(seq, size, grab_end=False):
result = []
queue = []
for item in seq:
if isinstance(item, int):
if len(queue) == size:
result.append(queue)
queue = queue[1:]
queue.append(item)
else:
if len(queue) == size:
result.append(queue)
queue = []
if grab_end and len(queue) == size:
result.append(queue)
return result

test1 = [
1, 3, 5, 'D',
1, 2, 3, 4, 5, 6, 7, 'A',
'S',
9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 'A',
]
test1r = [
[1, 2, 3, 4, 5, 6, 7],
[9, 8, 7, 6, 5, 4, 3],
[8, 7, 6, 5, 4, 3, 2],
[7, 6, 5, 4, 3, 2, 1],
[6, 5, 4, 3, 2, 1, 0],
]
test2 = [1, 2, 3, 4, 5]
test2r = [[1, 2, 3, 4, 5]] ### or is it [] ???
tests = [
(test1, test1r, 7, False),
(test2, [], 5, False),
(test2, test2r, 5, True),
]

failed = 0
for tno, (tseq, tresult, tsize, tgrab) in enumerate(tests):
aresult = took_num_range(tseq, tsize, grab_end=tgrab)
if aresult != tresult:
failed += 1
print 'Test %d failed' % (tno+1)
print 'Expected:', tresult
print 'Actual :', aresult
print 'Failed %d test(s) out of %d' % (failed, len(tests))

C:\junk>tooknumrange.py
Failed 0 test(s) out of 3

HTH,
John