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