Derek Koh
Derek Koh

Reputation: 3

Scope issues with for loops in python

In the following code, when I print the row in the first loop after doing a bunch of manipulations with it I see the results that I want. However, after I exit the first loop, I find that I get a different result in the variable Dataset. I know this is a scoping issue but I cannot figure out what the problem is and how to get my desired result which is shown with the first "print" statement. Thanks for your help

import random
random.seed(1234567)
Key=[[.5,.5]]
Dataset=[[0]+[0]*1]*int(10/2) +[[1]+[0]*1]*int(10/2)

print "results I need"
for row in Dataset:
    response=row[0]
    for i in xrange(len(Key)):
        if random.random() < Key[i][response]: 
            row[i+1]=response
        else: 
            row[i+1]=1-response
    print row

print "Results I get"
for row in Dataset:
    print row

Upvotes: 0

Views: 233

Answers (4)

shahjapan
shahjapan

Reputation: 14335

Its not a problem of scoping I think he wants to update the Dataset,

see the modified script below

import random
random.seed(1234567)
Key=[[.5,.5]]
Dataset=[[0]+[0]*1]*int(10/2) +[[1]+[0]*1]*int(10/2)

print "results I need"
for row in range(len(Dataset)): # Changes
    response=Dataset[row][0]
    for i in xrange(len(Key)):
        if random.random() < Key[i][response]:
            Dataset[row][i+1]=response # Important
        else:
            Dataset[row][i+1]=1-response # Important
    print Dataset[row]

print "Results I get"
for row in Dataset:
    print row

Upvotes: 0

Karl Knechtel
Karl Knechtel

Reputation: 61478

  • Python has reference semantics. Your original Dataset contains multiple references to the common [0, 0] and [1, 0] sublists. (I'm also at a loss to understand why you're making the initialization so complex.)

You could fix this by using [[0, 0] for i in xrange(5)] + [[1, 0] for i in xrange(5)].

  • The rest of your logic is also needlessly complex. We can use a conditional expression to merge the two assignments together, and we should be using direct iteration instead of iterating over an artificial list of indices (xrange).

That looks like:

for row in Dataset:
    response = row[0]
    for k in Key:
        row[i + 1] = response if random.random() < k[response] else 1 - response
  • However, this is still not the solution we're looking for. There's really no reason to put all those zeros in the initialization data that will be overwritten and never read in the loop. The [i + 1] indexing is also clumsy. A simpler solution: start with a list of just the first values for the sublists, and within the loop, construct the rest of each sublist (we can do this with a list comprehension) and prepend the first element. Instead of replacing the elements of the Dataset in place, we can use another list comprehension to bind them together.

That gives us:

import random
random.seed(1234567)
Key=[[.5,.5]]
Initial_Conditions=[0]*int(10/2) +[1]*int(10/2)

Dataset = [
    [i] + [
        i if random.random() < k[i] else 1 - i
        for k in Key
    ]
    for i in Initial_Conditions
]

Upvotes: 3

Raymond Hettinger
Raymond Hettinger

Reputation: 226181

The problem is in how the Dataset is constructed. It contents are not all unique lists -- several of them are identically the same object (not just the same contents). This is easy to fix:

Dataset=[[0,1] for i in range(10//2)] + [[1,0] for i in range(10//2)]

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798526

This is not a scoping issue at all. You've misconstructed Dataset, causing it to be composed of two sets of 5 references to the same list.

Dataset = [[0]+[0]*1 for x in range(10//2)] + [[1]+[0]*1 for x in range(10//2)]

Upvotes: 2

Related Questions