[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Sticky Variables: Terrain Loading



On Mar 12, 2008, at 3:39 AM, Kris Schnee wrote:

            for y in range(self.size):
                for x in range(self.size):
                    y = r and g

and in a later post:

The loop says "for y in range(something)." I thought that loops used each value in the list produced by the range statement, so that Python would be unaffected if I changed y during the loop.

note that you are changing y inside the inner loop with x, so when iterating the x values the y is not reset by the y iteration but i guess stays what you define it to be.

does this fully explain the peculiar behavior that you got .. and it had nothing to do with the 'terrain' reference being reused?

to get back to the other issue of object identities and references, what happens here is:

                    if b:
                        terrain = "water"
                    elif y:
                        terrain = "sand"
                    else:
                        terrain = "grass"
                    self.land.append(terrain)

EDIT: after writing the explanation attempt below, i realized that list append of course works so that an entry is added no matter what, also when a previous reference to the same object is in the list already. lists are not hashtables (like dictionaries are), that's the point kind of :) so:
>>> a = 1
>>> l = []
>>> l.append(a)
>>> l.append(a)
>>> l.append(a)
>>> l
[1, 1, 1]

anyhow, i post this explanation too, hoping that it is more helpful than confusing and not totally besides the point. you perhaps know all this but perhaps someone else here does not :)

every time you do: terrain = "somestring"
a new string object is created. "", like all literals (e.g. []), is in a way just a shorthand for instanciating a built-in type. using the normal object creation syntax the same would be; terrain = str("somestring")

strings in Python are immutable, i.e. they can not be changed. so you can never do terrain.something() so change the value of 'terrain'. that is kind of beside the point here though, as = just changes the ref anyway.

so what happens when you assign a new string to your variable/reference (terrain) is that the reference from it to the previous string is removed, and it is changed to refer the given object (with the value of e.g. "sand") instead. if there are no other references to the string that 'terrain' referred to previously, you have no way of getting a reference to it anymore and the garbage collector will remove the object from memory at some point.

therefore, when you get down to "self.land.append(terrain)", after such a if-elif-else structure where a new string object is always created, 'terrain' is *in principle* never the same object. *but*, like we already saw with smallish integers, there's a similar re-use optimization for strings apparently:
>>> long1 = "water is wet"
>>> long2 = "water is wet"
>>> long1 is long2
False
>>> short1 = "water"
>>> short2 = "water"
>>> short1 is short2
True

the point is, like some poster to this thread already said, that such implementation details do not matter in the application code. references to lists are added no matter what, that's how they work. dictionary keys are hashes of the values, whether references in dict assignments point to same memory or not is irrelevant.

and when in your own code you use == for values, and 'is' only when you actually want to check if two references are *made by your code* to be the same object, all works as expected. i mean cases like the scenenode.parent example i posted, basically these kind of things:
>>> o1 = object()
>>> o2 = o1
>>> o1 is o2
True

>>> l1 = ['a']
>>> l2 = ['b']
>>> l1.append(o1)
>>> l2.append(o1)
>>> l2.append(o2)
>>> l1[-1] is l2[-2]
True
>>> l1[-1] is l2[-1]
True
>>> l1, l2
(['a', <object object at 0x523b8>], ['b', <object object at 0x523b8>, <object object at 0x523b8>])

~Toni