Q about assignment and references

J

jdbosmaus

Pretty new to Python, but I thought I understood what is meant by "an
assignment is a reference."

Until I tried to understand this.

Here is a (fragment of an) event handler for a group of three wxPython
toggle buttons. The idea is to change the appearance of the label of
the button that was pressed, and reset the appearance of the other
two. Because all three buttons send messages to this handler, it uses
the event argument to figure out which button was activated. (In the
original there is additonal code that enforces some button-state
logic, but that's not relevant to this question so it has been
removed.)

Code:
def ScanModeHdlr(self, event):
        esource = event.GetEventObject() #return button that was
pressed

        fontUn = esource.Font
        fontSel = esource.Font
        fontUn.Style = wx.NORMAL
        fontSel.Style = wx.ITALIC
        fontUn.PointSize = 9
        fontSel.PointSize = 12

        btnlist = (self.TBN_NewScan, self.TBN_CheckScan,
self.TBN_ReScan)

        for x in btnlist:
            if x is esource:
                x.Font = fontSel
            else:
                x.Font = fontUn

Now, what bothers me is that in the 3rd and 4th lines, the RHS
"esource.Font" returns a wx.Font object that is a *copy* of the font
object of the button. The next four lines set the size and slant of
these objects - using semantics that ought to, in the ordinary Python
way, be changing "esource.Font". They don't, proving that fontUn and
fontSel are copies, not references. OK, esource.Font is a class
property, not a list, so maybe that's fair, though confusing. Then in
the for-loop we assign the font object to a LHS object that ...
semantically, looks exactly like the thing that returned a *copy* up
above. Not only that, but the for-loop variable "x" is assigned
sequentially to the button objects, yet the "is" comparison (which
does work as desired) proves that one value of x is the same *object*
as esource, not a copy - and look at line 2 where esource was
assigned.

I could understand if the setting-semantics in the for-loop needed to
be something like "x.SetFont(fontUn)", or even "x.SetFont = fontUn".
(for "could understand" read "would be much happier.")

I could also understand if the 3rd and 4th lines needed to look like
"fontUn = copy(esource.Font)". (which doesn't work; "copy" doesn't
know what to do.)

What I can't understand is how the semantics that actually works makes
sense in terms of Python's assignment conventions.

Can anybody square this circle for me? Thx...
 
C

Chris Rebert

Pretty new to Python, but I thought I understood what is meant by "an
assignment is a reference."

I recommend the effbot's treatment of the calling semantics:
http://effbot.org/zone/call-by-object.htm

....But I don't think that's the issue here.
Until I tried to understand this.
Here is a (fragment of an) event handler for a group of three wxPython

I believe the unintuitiveness here is due to quirks in the exact way
wxPython wraps wxWindows, not Python itself.
Code:
def ScanModeHdlr(self, event):
       esource = event.GetEventObject() #return button that was
pressed

       fontUn = esource.Font
       fontSel = esource.Font
       fontUn.Style = wx.NORMAL
       fontSel.Style = wx.ITALIC
       fontUn.PointSize = 9
       fontSel.PointSize = 12

       btnlist = (self.TBN_NewScan, self.TBN_CheckScan,
self.TBN_ReScan)

       for x in btnlist:
           if x is esource:
               x.Font = fontSel
           else:
               x.Font = fontUn

Now, what bothers me is that in the 3rd and 4th lines, the RHS
"esource.Font" returns a wx.Font object that is a *copy* of the font
object of the button.
Then in
the for-loop we assign the font object to a LHS object that ...
semantically, looks exactly like the thing that returned a *copy* up
above.
I could understand if the setting-semantics in the for-loop needed to
be something like "x.SetFont(fontUn)", or even "x.SetFont = fontUn".
(for "could understand" read "would be much happier.")
I could also understand if the 3rd and 4th lines needed to look like
"fontUn = copy(esource.Font)". (which doesn't work; "copy" doesn't
know what to do.)

In fact, I /suspect/ (I haven't used wxPython, so I can't be sure)
both of what you describe is /exactly/ what's going on here. wxPython
is /probably/ invoking the magic of properties
(http://docs.python.org/library/functions.html#property) to make
`esource.Font` return a copy and turn `esource.Font = fontUn` into a
setter method call behind the scenes.
What I can't understand is how the semantics that actually works makes
sense in terms of Python's assignment conventions.

Read about property() [see above link] and be enlightened. It
basically lets accesses and assignments to an attribute trigger method
calls; alternately, and probably more intuitively, you can look at it
as allowing a getter-setter pair to be presented (syntactically) like
a vanilla attribute.

Hence, esource.Font /looks/ like an attribute, but doesn't quack
[behave] like a normal one.

Cheers,
Chris
 
A

Alf P. Steinbach

* jdbosmaus:
Pretty new to Python, but I thought I understood what is meant by "an
assignment is a reference."

Until I tried to understand this.

Here is a (fragment of an) event handler for a group of three wxPython
toggle buttons. The idea is to change the appearance of the label of
the button that was pressed, and reset the appearance of the other
two. Because all three buttons send messages to this handler, it uses
the event argument to figure out which button was activated. (In the
original there is additonal code that enforces some button-state
logic, but that's not relevant to this question so it has been
removed.)

Code:
def ScanModeHdlr(self, event):
esource = event.GetEventObject() #return button that was
pressed

fontUn = esource.Font
fontSel = esource.Font
fontUn.Style = wx.NORMAL
fontSel.Style = wx.ITALIC
fontUn.PointSize = 9
fontSel.PointSize = 12

btnlist = (self.TBN_NewScan, self.TBN_CheckScan,
self.TBN_ReScan)

for x in btnlist:
if x is esource:
x.Font = fontSel
else:
x.Font = fontUn

Now, what bothers me is that in the 3rd and 4th lines, the RHS
"esource.Font" returns a wx.Font object that is a *copy* of the font
object of the button. The next four lines set the size and slant of
these objects - using semantics that ought to, in the ordinary Python
way, be changing "esource.Font". They don't, proving that fontUn and
fontSel are copies, not references. OK, esource.Font is a class
property, not a list, so maybe that's fair, though confusing.

As a property 'esource.Font' can produce a copy, yes.

Then 'fontUn' is set to refer to that new font object.

And 'fontSel' is set to refer to another new font object.

Then in
the for-loop we assign the font object to a LHS object that ...
semantically, looks exactly like the thing that returned a *copy* up
above.

You mean "syntactically, looks exactly". But whether it is depends on what it
is. If it's a simple attribute then it's just like a simple assignment. But most
likely it's a property because the assignment needs to have the side effect of
updating the button's screen presentation. And as a property it may copy the
font object or not. The syntax doesn't tell you. The documentation may tell you.

Not only that, but the for-loop variable "x" is assigned
sequentially to the button objects, yet the "is" comparison (which
does work as desired) proves that one value of x is the same *object*
as esource, not a copy - and look at line 2 where esource was
assigned.

No problem here. 'btnList' is a 'tuple' array of three object references. x is
assigned each reference in turn. Since it is a simple assignment to a variable
no "behind the scenes" actions are possible. It's just simple references.

I could understand if the setting-semantics in the for-loop needed to
be something like "x.SetFont(fontUn)", or even "x.SetFont = fontUn".
(for "could understand" read "would be much happier.")

Well, I don't think those names connote copying.

I could also understand if the 3rd and 4th lines needed to look like
"fontUn = copy(esource.Font)". (which doesn't work; "copy" doesn't
know what to do.)

Don't know about that. It's not a language problem though. It's about the wex
design.

What I can't understand is how the semantics that actually works makes
sense in terms of Python's assignment conventions.

Can anybody square this circle for me? Thx...

Assignments to plain variables are simple reference copyings.

Assignment to a property can do anything (including just printing "Hello, world!").

Using a property in an expression, e.g. on the rhs of an assignment, can
likewise do anything. It all depends on the properties in question. Or as Niels
Bohr remarked when asked how many tails a dog has, "It depends on the dog".


Cheers & hth.,

- Alf
 
J

jdbosmaus

Thanks to all for the informative answers.
You made me realize this is a wxPython issue. I have to say, wxPython
seems useful, and I'm glad it is available - but it doesn't have the
gentlest of learning curves.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top