开发者

Python List Error

开发者 https://www.devze.com 2023-01-28 23:08 出处:网络
I was writing a simple genetic program to test out the process, but got the following error: Traceback (most recent call last):

I was writing a simple genetic program to test out the process, but got the following error:

Traceback (most recent call last):
  File "evolution.py", line 43, in <module>
    nextgen += test[operator.indexOf(list(fits), m+chance)]
TypeError: iteration over non-sequence

on the code:

#!/usr/bin/env python

import random
import operator

mutationchance = 0.01
simtime        = 1000

# quadratic optimizer
class Organism:
    def __init__(self, x):
        self.x = x
        self.a = 1
        self.b = 2
        self.c = 3
        self.epsilon = 0.01
    def fitness(self):
        return self.a*(self.x**2) + self.b*(self.x) + self.c
    def mutate(self):
        self.x += random.random() - 0.5
    def describe(self):
        return self.x

def condmutate(org, chance):
    if random.random() <= chance:
        org.mutate()
    return org

test = [Organism(i) for i in range(-10, 10)]    

generation = 0

while generation < simtime:
    fits = [test开发者_JAVA技巧[i].fitness() for i in range(0, len(test) - 1)]
    sumf = sum(fits)
    i = 0
    nextgen = list()
    while i < len(fits) / 2:
        chance = random.random() * sumf
        j = 0
        shg = [fits[i] - chance for i in range(0, len(test) - 1)]
        m = min(shg)
        nextgen += test[operator.indexOf(list(fits), m+chance)]
        nextgen += test[operator.indexOf(list(fits), m+chance)]
    test = [condmutate(test[i], mutationchance) for i in range(0, len(nextgen) - 1)]
    generation += 1

print "result: ", max([test[i].describe() for i in range(0, len(test) - 1)])

I am new to Python, so it may just be a newbie mistake.


To add an element into nextgen, use nextgen.append(...) instead. += is the wrong operator.

Specifically, += on a list concatenates it with another iterable, not element.


I'm not sure exactly what's going on here, but to add items to a list you should use "append". You can also probably simplifiy your code a bit to make it more readable and maintainable.

Try changing:

nextgen += test[operator.indexOf(list(fits), m+chance)]

to:

nextgen.append(test[fits.indexOf(m+chance)])

But maybe I'm missing something and you have a good reason to use the "operator" module and re-wrap your list in a list?


You have several list comprehensions in your code of the form:

[test[i].fitness() for i in range(0, len(test) - 1)]

Please don't do this. It's a serious abuse of how iteration is supposed to work in Python.

Creating an index and then using it to index a list is horribly indirect. Imagine if you asked me to crack a dozen eggs, and I responded by writing the numbers 0 through 11 on a piece of paper, and then looking at each number in turn, counting along the egg carton to the corresponding slot, pulling out the egg and cracking it. The paper is a useless distraction. Just crack the eggs.

Further, range does not include the endpoint. range(0, 4) produces the list [0, 1, 2, 3]. Thus, your iteration skips the last element of the list. I can't tell whether this is deliberate or not.

If you want to iterate over every element:

[item.fitness() for item in test]

If you want to iterate over every element except the last:

[item.fitness() for item in test[:-1]]

I also can't tell what you're doing with the while i < len(fits) / 2: loop. How exactly are you expecting i to change? You haven't written anything that changes i, except the list comprehensions. If you weren't aware that list comprehensions "leak" their iteration variable into the local variable dictionary, then you're in for a nasty surprise. (If you need to prevent such a leak, you can use a generator comprehension; if you need a list, you can create a list from the generator comprehension, e.g. list(x for x in whatever).) If you were aware, and are depending on that behaviour, you're writing needlessly tricky code. Don't be clever. Explicit is better than implicit.


As others have pointed out, you should use nextgen.append(...) rather than += and much of the code could be cleaned up for clarity and simplicity. In addition, it appears that the variable chance is not really used, since you first subtract it and then add it back again. As a result, you will always append the minimum fitness element and there is no randomness in your code.

0

精彩评论

暂无评论...
验证码 换一张
取 消