Changing global variables in tkinter/pmw callback

Alex Martelli aleaxit at yahoo.com
Thu Apr 5 08:08:50 EDT 2001


"Brian Elmegaard" <be at mek.dtu.dk> wrote in message
news:3ACC4EB1.376225AF at mek.dtu.dk...
    [snip]
> non-CS-engineer it's too hard to get a meaningful explanation. Can it be
> written in a few words, so I may understand why lists are (and have to
> be) so different from "normal" variables?
    [snip]
> > I'll leave it to alex to write the long, pedagogical explanation.
>
> Looking forward to it.

Hmmm, OK, let's have a try.  The Python world is made up of "objects",
aka "values", and "references", that are bound to those objects.  OK
so far?

All you can do to a 'reference' is bind it to some object.  If a
reference was already bound to an object, and you are now binding
it to another object, this is also called 're-binding' the reference.

Binding (and re-binding) is most often done through the so-called
"assignment statement": the reference that is affected is indicated
by what is on the left of the '=' sign in such a statement, the
object being bound, by what is on the right of said sign.

(For completeness: "un-binding" a reference is also possible; the
'del' statement is used for that purpose; a reference 'exists' if
and only if it's bound to some object -- it starts 'existing' when
a binding is first done, it ceases to 'exist' if and when un-bound;
conversely, one could also say that an object exists if and only
if one or more references are bound to it, and be _almost_ right).


The key thing to remember: in se and per se, the fact of re-binding
a reference, which was previously bound to object X, so that it is
now bound to object Y, _has NO observable effect on either X or Y_
(except for such things as the possible 'side effect' of an object
going away completely if no references whatsoever are bound to it,
a garbage-collection issue which may work differently in different
Python implementations).


Some objects can 'contain' references: for example, if an object
has "attributes", you can think of those as references which have
names and are contained by the object; what you can think of as
(global) variables are nothing more (and nothing less) than the
attributes of an object (a module-object, i.e., an object whose
type is types.ModuleType).  [_Local_ variables of a function are
treated in a special way -- in some sense, they 'exist' even when
not yet bound, which is why you can get an UnboundLocalError if
you refer to them when they are not bound].

Not all references 'contained' in an object need be there as named
attributes of the object.  A dictionary object contains 'items',
which are key-value pairs: each key, and each value, is a reference.
A list object contains 'items' which are just references, held in
some specific order and identifiable by progressive number ('index').

Some objects are *mutable*, which means their state may be
changed (others, such as strings, tuples, and numbers, are
immutable).


So, coming to your original example, you had:
"""
In apply I do:
         def apply(self,button,buttons,setting):
             setting= button.cget('text')
"""
The body of this 'apply' is just re-binding a reference which
happens to be a local variable of this apply function.  It is,
specifically, an 'argument' of it, but arguments are just local
variables whose initial binding on a given function-call is
effected before the function-body starts executing (to either
default values, or values supplied by the caller).

Re-binding a local variable (be it an argument, or not) can
never have any possible effect on anything outside this
specific function, anyway.  This is a simple consequence
of what I identified above as "the key thing to remember":
re-binding a reference affects only that reference, NOT the
object which that reference happened to be previously bound to.


You say you now changed things:
"""
I use a list instead of a "variable" for the CurrentCanvasSetting. This
allows me to use it as a global variable, and I can get the wanted
"""

I _think_ you mean you are now doing something like:
    def apply(self,button,buttons,setting):
        setting[0] = button.cget('text')

This is re-binding, *NOT* the (local-variable) reference
named 'setting', but, rather, the (indexed) "0-th slot"
of whatever (e.g., a list) 'setting' is bound to.  This
*mutates* the object that 'setting' is bound to -- thus,
it may indeed be 'observable from outside', since there
may be any number of other references to said object,
besides the local one (argument) named 'setting'.

You are re-binding a reference *CONTAINED* in the object
that 'setting' is bound to: and that is the crucial
difference.  It's not between "lists" and "variables":
you could perfectly well mutate a module-object by
re-binding one of its variables (named attributes),
just as you can mutate a list-object by re-binding one
of its items (indexed 'slots').  To achieve such an
effect, you would pass the module-object as 'setting'
argument to this 'apply', then have a body such as:
    setting.foobar = button.cget('text')

(Or, you could use a 'grab-bag instance object' -- it
does not have to be a module-object; see for example
http://www.activestate.com/ASPN/Python/Cookbook/Recipe/52308).


Alex






More information about the Python-list mailing list