0

I'm new to Python (previously did some Perl). I'm a bit confused about how to live without "for" loop's variable not being local to the loop :) The question is in general how to use it without it biting me at some point, and in my example below in particular (now TestCase "keeps" notes from previous execution) -- or am I trying to do something silly there?

I guess in that for loop I could somehow undefine Name and TestCase. But what if it was a rather complex block of code, with continue-s etc.. how would I ensure Name and TestCase are always "clean" in the beginning on the loop?

class Result():
    def __init__(self, result, notes=[]):
        self.Res = result
        self.Notes  = notes   # List of strings
    # ...

def ExecTest1(p):
    ret = Result(PASS)
    # ...
    ret.FAIL('some note') # appends string as list item to Notes
    return ret

def ExecTest1(p):
    ret = Result(PASS)
    return ret

for Name, TestCase in {
        'Negative test': ExecTest1( param ),
        'Positive test': ExecTest1( another_param ),
    }.iteritems():

    print Name, TestCase.Res   # string
    print TestCase.Notes       # list
Kevin
  • 74,910
  • 12
  • 133
  • 166
flamey
  • 2,311
  • 4
  • 33
  • 40
  • It looks like all instances of `Result` refer to the same instance of `PASS`. Perhaps you need to take a copy of it. If you showed all the code then we wouldn't have to guess. – David Heffernan Sep 16 '14 at 14:45
  • 4
    '_TestCase "keeps" notes from previous execution_'. What do you mean by that? TestCase should have a brand new value in each iteration. If you're getting strange results, it may be due to the [default mutable argument](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) phenomenon in your `def __init__(self, result, notes=[]):` function. – Kevin Sep 16 '14 at 14:45
  • surely they will be clean at the start of the loop. After the loop exits the last value will remain in them though – user3684792 Sep 16 '14 at 14:46
  • Python has no block scope (http://stackoverflow.com/questions/6167923/block-scope-in-python). But the LCV's are local to the function, so they won't overwrite any external variables. It should be harmless to leave them around at the end of the function, or reuse them for another loop. I think your Perl training has made you see a problem where there isn't one - it's just different, not worse. – Mark Reed Sep 16 '14 at 14:51

1 Answers1

1

What you are actually seeing here is a feature of mutable default arguments, nothing to do with the scope of a for loop.

class Result():
    def __init__(self, result, notes=[]):
        self.Res = result
        self.Notes  = notes   # List of strings
    # ...

Here the default argument for notes is the same list used every time you don't specify another list. When you append a value to that list the value will still be there in every other instance of Result.

What you want to do instead is:

class Result():
    def __init__(self, result, notes=None):
        self.Res = result
        self.Notes  = notes if notes is not None else []  # List of strings
    # ...

as that will create a new empty list whenever the default None value is used for notes.

Default arguments for functions are computed when the function is defined. i.e. when the def statement is executed. The resulting object is saved as part of the function and is reused whenever the function is called.

You can read more about this in the Python FAQ

Duncan
  • 92,073
  • 11
  • 122
  • 156