2010-05-13 1 views
0

У меня есть скрипт, который содержит два класса. (Я, очевидно, удаляю много вещей, которые, как я полагаю, не имеют отношения к ошибке, с которой я имею дело.) В конечном итоге задача состоит в создании дерева решений, как я упоминал в вопросе this.Бесконечный цикл при добавлении строки в список в классе в python3

К сожалению, я получаю бесконечный цикл, и мне сложно определить причину. Я определил строку кода, которая идет haywire, но я бы подумал, что итератор и список, который я добавляю, будут разными объектами. Есть ли побочный эффект функциональности списка .append, о котором я не знаю? Или я делаю еще одну ослепительно очевидную ошибку?

class Dataset: 
    individuals = [] #Becomes a list of dictionaries, in which each dictionary is a row from the CSV with the headers as keys 
    def field_set(self): #Returns a list of the fields in individuals[] that can be used to split the data (i.e. have more than one value amongst the individuals 
    def classified(self, predicted_value): #Returns True if all the individuals have the same value for predicted_value 
    def fields_exhausted(self, predicted_value): #Returns True if all the individuals are identical except for predicted_value 
    def lowest_entropy_value(self, predicted_value): #Returns the field that will reduce <a href="http://en.wikipedia.org/wiki/Entropy_%28information_theory%29">entropy</a> the most 
    def __init__(self, individuals=[]): 

и

class Node: 
    ds = Dataset() #The data that is associated with this Node 
    links = [] #List of Nodes, the offspring Nodes of this node 
    level = 0 #Tree depth of this Node 
    split_value = '' #Field used to split out this Node from the parent node 
    node_value = '' #Value used to split out this Node from the parent Node 

    def split_dataset(self, split_value): #Splits the dataset into a series of smaller datasets, each of which has a unique value for split_value. Then creates subnodes to store these datasets. 
     fields = [] #List of options for split_value amongst the individuals 
     datasets = {} #Dictionary of Datasets, each one with a value from fields[] as its key 
     for field in self.ds.field_set()[split_value]: #Populates the keys of fields[] 
      fields.append(field) 
      datasets[field] = Dataset() 
     for i in self.ds.individuals: #Adds individuals to the datasets.dataset that matches their result for split_value 
      datasets[i[split_value]].individuals.append(i) #<---Causes an infinite loop on the second hit 
     for field in fields: #Creates subnodes from each of the datasets.Dataset options 
      self.add_subnode(datasets[field],split_value,field) 

    def add_subnode(self, dataset, split_value='', node_value=''): 
    def __init__(self, level, dataset=Dataset()): 

Мой код инициализации в настоящее время:

if __name__ == '__main__': 
    filename = (sys.argv[1]) #Takes in a CSV file 
    predicted_value = "# class" #Identifies the field from the CSV file that should be predicted 
    base_dataset = parse_csv(filename) #Turns the CSV file into a list of lists 
    parsed_dataset = individual_list(base_dataset) #Turns the list of lists into a list of dictionaries 
    root = Node(0, Dataset(parsed_dataset)) #Creates a root node, passing it the full dataset 
    root.split_dataset(root.ds.lowest_entropy_value(predicted_value)) #Performs the first split, creating multiple subnodes 
    n = root.links[0] 
    n.split_dataset(n.ds.lowest_entropy_value(predicted_value)) #Attempts to split the first subnode. 

ответ

4
class Dataset: 
    individuals = [] 

Подозрительно. Если вы не хотите, чтобы список статических членов был общим для всех экземпляров Dataset, вы не должны этого делать. Если вы устанавливаете self.individuals= something в __init__, то здесь вам также не нужно устанавливать individuals.

def __init__(self, individuals=[]): 

Все еще подозрительно. Вы назначаете аргумент individuals для self.individuals? Если это так, вы назначаете тот же список individuals, созданный во время определения функции, каждому Dataset, который создается с аргументом по умолчанию. Добавьте элемент в один список Dataset, и все остальные, созданные без явного аргумента individuals, тоже получат этот элемент.

Аналогично:

class Node: 
    def __init__(self, level, dataset=Dataset()): 

Все Node s созданные без явного dataset аргумента получит точный экземпляр же по умолчанию Dataset.

Это mutable default argument problem, и вид деструктивных итераций, которые он произвел бы, по-видимому, может вызвать бесконечный цикл.

+0

+1 Хороший ответ. –

4

Я подозреваю, что вы добавления в этом же списке, что вы Перебор, заставляя его увеличиваться в размерах, прежде чем итератор может дойти до конца. Попробуйте итерация копию списка вместо:

for i in list(self.ds.individuals): 
    datasets[i[split_value]].individuals.append(i) 
+0

Есть ли у Python 3 оператор slice? IE для i in self.ds.individuals [:]: other_code ? – mcpeterson

+0

@McPeterson, ломтики все еще работают в Python3 –