Re: a couple of things I don't understand wrt lists
Hello, I am still in the process of writing preliminary code for my CA project. I am now running into a behavior that I can't explain. Here is a script which, at least on my system, shows the issue (python2.7 on a linux system). The final project will be wrapping these functions (and others) into a class which will be in a module which can be imported into a script. #!/usr/bin/python2 import sys import random def get_rule(rulenum): bitpattern = bin(rulenum)[2:] return [0]*(8-len(bitpattern)) + [int(bit) for bit in bitpattern] def populate(n): random.seed() return [random.randint(0,1) for i in range(n)] def get_index(thisgen, i): n = len(thisgen)-1 cell = thisgen[i] if i is 0: print i==0 prev, next = thisgen[n], thisgen[i+1] elif i is n: print i==%d % n prev, next = thisgen[i-1], thisgen[0] else: prev, next = thisgen[i-1], thisgen[i+1] return prev*4 + cell*2 + next def get_nextgen(thisgen, rule): return [rule[get_index(thisgen, i)] for i in range(len(thisgen))] if len(sys.argv) == 2: n = int(sys.argv[1]) else: n = 257 rule = get_rule(145) thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) print done for n == 257 n = 258 thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) My issue is that when n == 257, the script runs as expected, but if n = 258, I get an IndexError: list index out of range. The script is also attached to the email in case someone would like to try it on their machine. The print statements in the get_index() function's branching show me that, when I get the out of range error, the program doesn't enter the elif i is n condition, although it does for lower values of n. I'm sorry, but I still haven't found a way to copy/paste from the terminal to vim. This behaviour occurred previously and had stopped when I used an other version of the get_index() function. At that time, get_index() wasn't a function and was just conditional branching inside get_nextgen, I wanted to use the list comprehension syntax to build nextgen, and this got me into seperating the get_index() routine. #!/usr/bin/python2 import sys import random def get_rule(rulenum): bitpattern = bin(rulenum)[2:] return [0]*(8-len(bitpattern)) + [int(bit) for bit in bitpattern] def populate(n): random.seed() return [random.randint(0,1) for i in range(n)] def get_index(thisgen, i): n = len(thisgen)-1 cell = thisgen[i] if i is 0: print i==0 prev, next = thisgen[n], thisgen[i+1] elif i is n: print i==%d % n prev, next = thisgen[i-1], thisgen[0] else: prev, next = thisgen[i-1], thisgen[i+1] return prev*4 + cell*2 + next def get_nextgen(thisgen, rule): return [rule[get_index(thisgen, i)] for i in range(len(thisgen))] if len(sys.argv) == 2: n = int(sys.argv[1]) else: n = 257 rule = get_rule(145) thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) print done for n == 257 n = 258 thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 04/18/2013 09:01 AM, aaB wrote: Hello, I am still in the process of writing preliminary code for my CA project. I am now running into a behavior that I can't explain. Here is a script which, at least on my system, shows the issue (python2.7 on a linux system). The final project will be wrapping these functions (and others) into a class which will be in a module which can be imported into a script. #!/usr/bin/python2 import sys import random def get_rule(rulenum): bitpattern = bin(rulenum)[2:] return [0]*(8-len(bitpattern)) + [int(bit) for bit in bitpattern] def populate(n): random.seed() return [random.randint(0,1) for i in range(n)] def get_index(thisgen, i): n = len(thisgen)-1 cell = thisgen[i] if i is 0: print i==0 prev, next = thisgen[n], thisgen[i+1] elif i is n: Don't use 'is' here and above. You're not looking for a matching object, you're looking for the same value. print i==%d % n prev, next = thisgen[i-1], thisgen[0] else: prev, next = thisgen[i-1], thisgen[i+1] return prev*4 + cell*2 + next def get_nextgen(thisgen, rule): return [rule[get_index(thisgen, i)] for i in range(len(thisgen))] if len(sys.argv) == 2: n = int(sys.argv[1]) else: n = 257 rule = get_rule(145) thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) print done for n == 257 n = 258 thisgen = populate(n) nextgen = get_nextgen(thisgen, rule) My issue is that when n == 257, the script runs as expected, but if n = 258, I get an IndexError: list index out of range. No, you get an exception traceback. Please paste in the whole traceback instead of making everyone guess where in the code it might be getting the exception. My *guess* is that somewhere you're assuming that 8 bits is enough to encode 258 possibilities. I'd have expected that to fail at 256 and larger, but it's a place to look. The second guess, more likely, is that you're using is to compare numbers, and that's never a safe idea. It might happen to work for small numbers, but you should be using ==. if i == 0: elf i == n: The script is also attached to the email Attachments aren't necessarily visible to everyone reading the mailing list. Just make sure you post in text mode (which you did), and that should take care of spurious indentation bugs. -- DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
The second guess, more likely, is that you're using is to compare numbers, and that's never a safe idea. It might happen to work for small numbers, but you should be using ==. The second guess was right, changing is for == solved it, thanks. I still have a lot to learn about python semantics. The 8 bit pattern is used to store the rule, not the cells. To compute the next cell, I index the rule list, based on the values of that cell and it's two immediate neighbours in the previous generation. This probably isn't the simplest way. Since I am using only 3 cells to compute 1 cell, the biggest index would be 2**3 - 1, hence the 8bit pattern for the rule. -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On Thu, Apr 18, 2013 at 11:01 PM, aaB mecagonoisic...@gmail.com wrote: def get_index(thisgen, i): n = len(thisgen)-1 cell = thisgen[i] if i is 0: print i==0 prev, next = thisgen[n], thisgen[i+1] elif i is n: print i==%d % n prev, next = thisgen[i-1], thisgen[0] else: prev, next = thisgen[i-1], thisgen[i+1] return prev*4 + cell*2 + next Without seeing the exception traceback I can't be sure, but here's what I think might be happening: When n == 258, your i is n check never happens. Since your protective check for the end of the list doesn't fire, you therefore go into the 'else' clause, and attempt to index thisgen[i+1], which doesn't work. CPython precreates and caches a certain subset of integers, for performance. The exact set depends on the CPython version, but it's low integers only. Within that set, equality is always matched by identity: i = 3 j = i+1 k = j-1 print(i is k) This will most likely print True on CPython. But change i to, say, 1000, and you may find the opposite result. So you can sometimes get away with the dangerous option of testing integers for identity, but the right thing to do is to test for equality. (You even get that right in your debugging messages, using == there.) A couple of other tips: n = len(thisgen)-1 if i is 0: prev, next = thisgen[n], thisgen[i+1] You can reference thisgen[-1] instead of thisgen[n] - so you can fold this one into the default case. So all you need to do is deal with the one possibility that i==len(thisgen)-1 and everything else is in the else. def populate(n): random.seed() return [random.randint(0,1) for i in range(n)] Don't reseed your RNG every call; just seed it once and let it run. Seeding the RNG (without using a specific value, which you're not doing here) is done in one of two ways: either from an OS-supplied source of randomness (eg /dev/random), or from the time of day. Reseeding repeatedly from /dev/random is unnecessary and might impact other processes (forcing them to block for lack of available entropy); reseeding from the time of day could mean that every call to populate() returns the exact same sequence of numbers. Have fun! ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
17.04.13 07:57, Larry Hudson написав(ла): So using a list comprehension you can do it in two lines: def get_rule(num): bs = bin(num)[2:] return [0] * (8 - len(bs)) + [int(i) for i in bs] You can do it in one line! def get_rule(num): return list(map(int, '{:08b}'.format(num))) -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
Hello, Thanks for all your replies, things are getting clearer. - copy/paste vs retyping: Several people have remarked that I had retyped instead of copy/pasting. This is exactly what happened, the fact is I haven't figured out yet how to enable copy/pasting from urxvt to vim. I'll try to get this done before posting output from an interactive session. - iterating a list: If I understand what you've told me, bitpattern = [1, 0, 0, 1, 1, 0, 1] for bit in bitpattern: print bit and bitpattern = [1, 0, 0, 1, 1, 0, 1] for i in range(len(bitpattern)): print bitpattern[i] are equivalent, the former being more python and the latter being something like C written using python syntax. - the complement thing: I haven't yet tried to reproduce this, but I will, and I will post back if I see this happening again, this time with a real log of python's interactive console, or a complete script which people can use. - list comprehension: I wasn't at all aware of this, thanks a lot for pointing it out. I had an other function that generated a list of cells for the CA, each cell being randomly alive or dead. I have rewritten it using list comprehension, def populate(n): random.seed() return [random.randint(0,1) for i in range(n)] which works the same as my previous, C-like, version but feels much better. I might come back to you all but you've already given me a good push forward, so I guess I'll be trying to use it as much as I can before asking for an other. -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
aaB mecagonoisic...@gmail.com writes: - copy/paste vs retyping: Several people have remarked that I had retyped instead of copy/pasting. This is exactly what happened, the fact is I haven't figured out yet how to enable copy/pasting from urxvt to vim. I used to use rxvt, but since a while I switched to roxterm for exactly that annoying problem: I may be wrong, but urxvt uses only the ancient X cutpaste way of selecting a region with the mouse and then using the middle mouse button to paste it back. ciao, lele. -- nickname: Lele Gaifax | Quando vivrò di quello che ho pensato ieri real: Emanuele Gaifas | comincerò ad aver paura di chi mi copia. l...@metapensiero.it | -- Fortunato Depero, 1929. -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On Apr 17, 5:25 am, aaB mecagonoisic...@gmail.com wrote: - the complement thing: I haven't yet tried to reproduce this, but I will, and I will post back if I see this happening again, this time with a real log of python's interactive console, or a complete script which people can use. That was happening when you incorrectly used bit as an index back into bitpattern. When you do that, the behavior actually changes depending on the value of bitpattern: a bitpattern that starts with [1, 0, ...] will yield its complement: bitpattern = [1, 0, 0, 1, 1, 0, 1] for bit in bitpattern: print 'bitpattern[%s] : %s' % (bit, bitpattern[bit]) bitpattern[1] : 0 bitpattern[0] : 1 bitpattern[0] : 1 bitpattern[1] : 0 bitpattern[1] : 0 bitpattern[0] : 1 bitpattern[1] : 0 while a bitpattern that starts with [0, 1, ...] will yield the expected results: bitpattern = [0, 1, 0, 1, 1, 0, 1] for bit in bitpattern: print 'bitpattern[%s] : %s' % (bit, bitpattern[bit]) bitpattern[0] : 0 bitpattern[1] : 1 bitpattern[0] : 0 bitpattern[1] : 1 bitpattern[1] : 1 bitpattern[0] : 0 bitpattern[1] : 1 HTH, Don -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
Serhiy Storchaka於 2013年4月17日星期三UTC+8下午5時35分07秒寫道: 17.04.13 07:57, Larry Hudson написав(ла): So using a list comprehension you can do it in two lines: def get_rule(num): bs = bin(num)[2:] return [0] * (8 - len(bs)) + [int(i) for i in bs] You can do it in one line! def get_rule(num): return list(map(int, '{:08b}'.format(num))) Well, a new object is returned and can be used. Then who is going to clean up the object when required? -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 4/17/2013 12:10 PM, 8 Dihedral wrote: Serhiy Storchaka於 2013年4月17日星期三UTC+8下午5時35分07秒寫道: 17.04.13 07:57, Larry Hudson написав(ла): So using a list comprehension you can do it in two lines: def get_rule(num): bs = bin(num)[2:] return [0] * (8 - len(bs)) + [int(i) for i in bs] You can do it in one line! def get_rule(num): return list(map(int, '{:08b}'.format(num))) Well, a new object is returned and can be used. Then who is going to clean up the object when required? This is a key thing to understand about Python: memory is managed automatically, no one has to clean up the object. Once there are no names referring to the object, it will be cleaned up automatically. --Ned. -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On Thu, Apr 18, 2013 at 4:36 AM, Ned Batchelder n...@nedbatchelder.com wrote: On 4/17/2013 12:10 PM, 8 Dihedral wrote: Well, a new object is returned and can be used. Then who is going to clean up the object when required? This is a key thing to understand about Python: memory is managed automatically, no one has to clean up the object. Once there are no names referring to the object, it will be cleaned up automatically. Dihedral is a bot. An amusing one, at times, but not someone you need overly concern yourself with. :) ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
Ned Batchelder wrote: On 4/17/2013 12:10 PM, 8 Dihedral wrote: Well, a new object is returned and can be used. Then who is going to clean up the object when required? This is a key thing to understand about Python: memory is managed automatically, no one has to clean up the object. Once there are no names referring to the object, it will be cleaned up automatically. The key to understand about 8 Dihedral is that it is a bot. :-) But seriously, it's a bot. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
a couple of things I don't understand wrt lists
hello, I am a beginner programmer. I started learning programming about a year and a half ago, using C. I picked up python a few months ago, but only wrote very few scripts. I am currently trying to learn more about the python way of doing things by writing a script that generates png images using a 1D cellular automaton. While writing preliminary code for that project, I ran into a behaviour that I don't understand. I am using python 2.7 on a linux system. I represent the CA's rule with a list of integers, of value 1 or 0. Here is the function I use to generate the list: def get_rule(rulenum): rule = [] while rulenum 0: rule.append(rulenume % 2) rulenum /= 2 while len(rule) 8: rule.append(0) rule.reverse() return rule if i call it by writing: rule = getrule(int(8)) and then call: print rule the output is good: [0, 0, 0, 0, 1, 0, 0, 0] I then tried to print each item of the list using a for loop: for i in range(rule): print rule[i] the output is, as expected: 0 0 0 0 1 0 0 0 but when I do: for i in rule: print rule[i] I get the complement: 1 1 1 1 0 1 1 1 There must be something I didn't understand correctly in the for statement, but I really can't think of a reason why the output is what it is. I tried this using the interactive console, and the results are the same, whatever the length of the list, i always get the complement of my bit pattern. Any pointers to help me understand this would be appreciated. I am also running into an other issue with this script, but I'd rather understand this before asking further questions. Thanks, and sorry for the rather long post. -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On Wed, Apr 17, 2013 at 1:37 AM, aaB mecagonoisic...@gmail.com wrote: but when I do: for i in rule: print rule[i] When you iterate over rule, you don't iterate over the indices, but over the values themselves. Try this: for i in rule: print i Incidentally, for i in range(rule) isn't actually going to work; what you would have used is for i in range(len(rule)). Be careful with that sort of thing; it's usually safest to actually copy and paste from an interactive session, rather than reconstruct manually. Sometimes it's not obvious whether it was a copy/paste problem or the cause of your underlying confusion. ChrisA -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
In mailman.668.1366126626.3114.python-l...@python.org aaB mecagonoisic...@gmail.com writes: but when I do: for i in rule: print rule[i] I get the complement: 1 1 1 1 0 1 1 1 When you iterate over a list with this statement: for i in rule: i contains each successive list item. However, your code: print rule[i] acts as though i is the list item's *subscript*, which is incorrect. In effect, your code is doing this: print rule[0] print rule[0] print rule[0] print rule[0] print rule[1] print rule[0] print rule[0] print rule[0] Although in your example both rule[0] and rule[1] are zero, so I don't know why '1' ever got printed. Also, as far as I can tell, this code should not have worked at all: for i in range(rule): print rule[i] The range() function expects an integer, not a list. -- John Gordon A is for Amy, who fell down the stairs gor...@panix.com B is for Basil, assaulted by bears -- Edward Gorey, The Gashlycrumb Tinies -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 4/16/2013 11:37 AM, aaB wrote: I represent the CA's rule with a list of integers, of value 1 or 0. Here is the function I use to generate the list: def get_rule(rulenum): rule = [] while rulenum 0: rule.append(rulenume % 2) rulenum /= 2 divmod(rulenum) will return both the quotient and remainder at one time while len(rule) 8: rule.append(0) rule.reverse() return rule In versions of Python with builtin bin(), you could write def get_rule(rulenum): b = bin(rulenum)[2:] # return [0]*(8-len(b)) + [int(i) for i in b] To know Python decently well, you should understand all of that syntax. rule = getrule(int(8)) print rule [0, 0, 0, 0, 1, 0, 0, 0] -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 04/16/2013 11:37 AM, aaB wrote: hello, I am a beginner programmer. I started learning programming about a year and a half ago, using C. I picked up python a few months ago, but only wrote very few scripts. I am currently trying to learn more about the python way of doing things by writing a script that generates png images using a 1D cellular automaton. While writing preliminary code for that project, I ran into a behaviour that I don't understand. I am using python 2.7 on a linux system. I represent the CA's rule with a list of integers, of value 1 or 0. Here is the function I use to generate the list: def get_rule(rulenum): rule = [] while rulenum 0: rule.append(rulenume % 2) rulenum /= 2 while len(rule) 8: rule.append(0) rule.reverse() return rule if i call it by writing: rule = getrule(int(8)) and then call: print rule the output is good: [0, 0, 0, 0, 1, 0, 0, 0] I then tried to print each item of the list using a for loop: There are copy/paste errors in your following pieces. Did you retype them instead of using the clipboard? for i in range(rule): print rule[i] the output is, as expected: 0 0 0 0 1 0 0 0 Here's what I get, and how I fix it: rule = [0,0,0,0,1,0,0,0] for i in range(rule): ... print i ... Traceback (most recent call last): File stdin, line 1, in module TypeError: range() integer end argument expected, got list. for i in range(len(rule)): ... print rule[i] ... 0 0 0 0 1 0 0 0 but when I do: for i in rule: print rule[i] You should be printing i here, not rule[i] I get the complement: 1 1 1 1 0 1 1 1 I don't. And don't expect to. It's nothing like the complement. for i in rule: ... print rule[i] ... 0 0 0 0 0 0 0 0 Anyway, to fix it, just print the value, don't try to use it as a subscript. for value in rule: ... print value ... 0 0 0 0 1 0 0 0 There must be something I didn't understand correctly in the for statement, but I really can't think of a reason why the output is what it is. I tried this using the interactive console, and the results are the same, whatever the length of the list, i always get the complement of my bit pattern. You should never get the complement of the bit pattern with any code you've shown above. Hope that helps. -- DaveA -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 04/16/2013 08:37 AM, aaB wrote: rule = getrule(int(8)) just rule = getrule(8) is sufficient -- you don't need to cast the integer 8 to an integer. ;) Thanks, and sorry for the rather long post. Not too long at all: it had lots of detail of what you were trying to do, what you were expecting, and what you got; it was darn near perfect. -- ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: a couple of things I don't understand wrt lists
On 04/16/2013 08:37 AM, aaB wrote: hello, snip I represent the CA's rule with a list of integers, of value 1 or 0. Here is the function I use to generate the list: def get_rule(rulenum): rule = [] while rulenum 0: rule.append(rulenume % 2) rulenum /= 2 while len(rule) 8: rule.append(0) rule.reverse() return rule It appears what you are trying to do is create an eight-element list corresponding to the binary value of rulenum. Here is a different approach, using some other functions and features of Python... First you can use the bin() function to get the binary value of an integer as a string. But this string has a leading '0b', which can be cut off with slicing. eg. (using your example value of 8 and bs as the variable name for the binary string) bin(8) gives the string '0b1000', so slicing off the two leading characters: bs = bin(8)[2:] bs becomes the string '1000' Now, the number of leading zeros needed is (8 - len(bs)). You can create the initial list of leading zeros with the statement: rule = [0] * (8 - len(bs)). This gives rule as the list [0, 0, 0, 0]. Finally use a for loop to append the rest if the binary string as integers for i in bs: rule.append(int(i)) So your function becomes (with a few changed variable names): def get_rule(num): bs = bin(num)[2:] rule = [0] * (8 - len(bs)) for i in bs: rule.append(int(i)) return rule This can be shortened even more with a list comprehension. You can think of a list comprehension essentially as a terse variation of a for loop specifically to create a list. So using a list comprehension you can do it in two lines: def get_rule(num): bs = bin(num)[2:] return [0] * (8 - len(bs)) + [int(i) for i in bs] Again, I'm assuming you specifically want an 8-element list. But this could easily be generalized for any length by adding a second function parameter, say size, and change the 8 in the last statement to size. snip Any pointers to help me understand this would be appreciated. I am also running into an other issue with this script, but I'd rather understand this before asking further questions. Thanks, and sorry for the rather long post. Don't worry about the length -- my reply is plenty wordy as well. I'm hoping I went into enough detail that you can understand it without it being too advanced. Mainly I was just trying to show you a different approach using other features of Python. There's nothing wrong with your approach, it is quite straight-forward. In fact I used the same basic approach when I was writing a C function to commify the display of integers -- that is, to add commas every third digit.(*) Just about anything in programming can be approached in several different ways. I'm not saying mine is better, and certainly not the best, just different. I'm not a newbie but FAR from an expert. Keep learning Python, I think you'll like it. (*)A special function for this isn't necessary in Python, it's already built in the the new-style string formatting. Try this statement: '{:,}'.format(100) (That's a colon and comma inside the curly braces.) -=- Larry -=- -- http://mail.python.org/mailman/listinfo/python-list