list mutability

G

gigs

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:[[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[[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
 
J

John Machin

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:[[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[[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.

Instead of
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]
?

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top