pygame - importing GL - very bad...

alex23 wuwei23 at gmail.com
Sun Jan 6 06:37:37 EST 2013


On Jan 6, 5:49 am, someone <newsbo... at gmail.com> wrote:
> I thought that python also used "true" pass-by-reference, although I
> haven't figured out exactly when I have this problem. I can just see
> that sometimes I get this problem and then I need to copy the variable,
> if I don't want the original data of the variable to be overwritten...

Generally I find it easier to call variables 'labels' or 'references';
you're not stashing a value into a slot, you're giving a name to an
object. So you're never really passing values around, just labels that
refer to an object.

The confusion kicks in because there are two types of object: mutable
and immutable. Mutable objects can change, immutable objects cannot.
Operations on an immutable object will return a _new_ immutable
object; the label used in an operation on an immutable object will
refer to the new object, any other references to the original object
will continue to refer to the original. Strings, numbers, tuples and
frozensets are all immutable built-in types.

    >>> a = "alpha"
    >>> b = a
    >>> a = a + "bet"
    >>> a
    'alphabet'
    >>> b
    'alpha'

With immutable types, you're safe to pass them into a function, act on
them, and not have references in the outer scope reflect the change:

    >>> def double(x): return x * 2
    ...
    >>> a = "alpha"
    >>> double(a)
    'alphaalpha'
    >>> a
    'alpha'

Everything else, including user defined objects, tend to be mutable:

    >>> a = dict(foo=1,bar=2)
    >>> b = a
    >>> a['foo'] = 99
    >>> a
    {'foo': 99, 'bar': 2}
    >>> b
    {'foo': 99, 'bar': 2}

With mutable objects, you're _always_ operating on the _same_ object
that everything is referring to, even when you pass it into a
different scope:

    >>> def toggle_foo( x ): x['foo'] = not x['foo']
    ...
    >>> a = dict(foo=True)
    >>> toggle_foo(a)
    >>> a
    {'foo': False}

Note that the `toggle_foo` function doesn't return anything, nor is
the value of a re-assigned. The object that a refers to is passed into
`toggle_foo`, modified in place, and all references to it remain
pointing to the same, now modified object.

This is one of the big causes of unexpected behaviour to new Python
users, but as you get a better understanding of how Python's object
model works, you'll see it's really quite consistent and predictable.

There are a couple of ways you can ensure you're always working with a
copy of an object if you need to. For lists, the canonical way is:

    >>> a = [1,2,3]
    >>> b = a
    >>> a = [1, 2, 3]
    >>> b = a[:] # shallow copy of a
    >>> b.append(99)
    >>> b
    [1, 2, 3, 99]
    >>> a
    [1, 2, 3]

`b = a[:]` uses slice notation to create a new list that contains
everything in the original list, from start to end. This is called a
"shallow" copy; `a` and `b` both refer to _different_ lists, but the
objects within are the _same_ objects. For numbers, this isn't
important, as they're immutable. For mutable objects, however, it's
something you need to bear in mind:

    >>> a = [ [1,2], [3, 4] ] # list of lists
    >>> b = a[:]
    >>> b[0][0] = 99
    >>> b
    [[99, 2], [3, 4]]
    >>> a
    [[99, 2], [3, 4]]

So here, while `b` refers to copy of `a`, that copy contains the
_same_ list objects that `a` does, so any changes to the internal
lists will be reflected in both references, while any changes to `b`
itself won't be:

    >>> b.append([5,6])
    >>> b
    [[99, 2], [3, 4], [5, 6]]
    >>> a
    [[99, 2], [3, 4]]

This is where the `copy` module comes to the rescue, providing a
shallow copy function `copy`, as well as `deepcopy` that makes copies
of all the objects within the object:

    >>> import copy
    >>> a = [ [1,2], [3, 4] ] # list of lists
    >>> b = copy.deepcopy(a)
    >>> b[0][0] = 99
    >>> b
    [[99, 2], [3, 4]]
    >>> a
    [[1, 2], [3, 4]]

If you plan on using the `copy` module, it's worthwhile readings it
docs, as there are some nuances to it that I'm glossing over here.
TBH, I don't recall every needing to use `copy` in my code.

Hope this helps bring consistency where you currently find confusion :)



More information about the Python-list mailing list