Tkinter callback arguments

G

Gabriel Genellina

* Steven D'Aprano:
For example, consider two rectangle classes R1 and R2, where R2 might
be a successor to R1, at some point in system evolution replacing R1.
R1 has logical data members left, top, width and height, and R2 has
logical data members left, top, right and bottom. With R1 direct
changes of left and top keeps the rectangle's size (since that size
is
specified by width and height), while with R2 it changes the
rectangle's size. R1 is implemented with logical data members as
directly exposed data attributes. Some code in the system deals only
with R1 objects and for convenience or efficiency or whatever uses
direct modification instead of set_position method. Due to new
requirements it instead has to deal with R2 objects, with same
methods. But due to the direct modification of object state it now
changes the rectangle sizes, but at first it's not noticed since the
attempted rectangle position changes are very small. People get
upset.
The bug is fixed. Time has been wasted.
If there is need for mutable rectangles, there is need for mutable
rectangles. Using properties instead of attributes doesn't help
In the example above using properties would have avoided the problem.
How would it have avoided the problem? Either of these would have the
exact same semantics:
class R2(object):
def __init__(self):
self._secret = {'top': 0, 'bottom': 100}
def _top_getter(self):
return self._secret['top']
def _top_setter(self, value):
self._secret['top'] = value
top = property(_top_getter, _top_setter)
vs
class R2(object):
def __init__(self):
self.top = 0
self.bottom = 100

OK, I had a laugh. :) You maintain that all doors are dark red, and
show up a photo of two of your dark red doors as proof.

For R2, did you at *any* moment consider properties that emulated the
internal representation of R1?

I'm putting it that way on the off-chance that you're not just
pretending to not understand.

I don't understand either. R1 and R2 have *different* semantics. They
don't behave the same. Any breakage you experiment using R2 instead of R1
comes from the fact they behave differently, not because they're
implemented differently, nor because they use properties or not.
You could have implemented another variant, let's say RCrazy, that behaves
exactly the same as R1 but internally stores a different set of attributes
(the baricenter, the angle between both diagonals, and the diagonal
length). As long as you implement the same public interfase (same set of
externally visible attributes, same methods, same behavior) RCrazy is
interchangeable with R1; RCrazy is a subtype of R1 in the sense of the
Liskov substitution principle.
Of course, perfect substitutability (did I spell it right?) isn't possible
in Python; obj.__class__.__name__ returns 'RCrazy' instead of 'R1', it's
mro() is different, dir() returns a different set of names, etc. But for
any `reasonable` use of an R1 instance representing a rectangle, an RCrazy
instance should serve equally well.
No semantics was specified in my example, quoted in full above.

However, the natural semantics is that various logical properties, such
as left, top, right, bottom, width and height, can be varied
independently.

You did specify the set of attributes and how they behave, perhaps not
very formally, but that's a semantic specification to me. It was clear
from your description that R2 behave different that R1; the problems that
came after using R2 instead of R1 were caused by such different behavior,
not because of using properties or not. In any case, I don't think the
problem is specific to Python.
Happily that's incorrect. You might try to consider what properties are
*for*, why the language supports them if they do nothing at all except
adding overhead.

In normal usage (either obj.name or getattr(obj, 'name')) an attribute is
undistinguishable from a property. Users of the class should not worry at
all whether it is implemented as a simple attribute, a computed property,
or an esoteric class attribute following the descriptor protocol.
If all a property does is to store and retrieve its value as an instance
attribute, yes, it just adds overhead.
 
P

Peter Otten

Alf said:
* Peter Otten:

No, I meant that I didn't understand why you find it hard to read and
understand.

Too many indirections.
[snip]
Couldn't

class IdButton(tkinter.Button):
def __init__(self, id, **kw):
self.id = id
tkinter.Button.__init__(self, **kw)

be customised as easily?

Not unless there's much more that I can learn about tkinter button
'command' callbacks. Which is of course possible. :) Is it possible to
pick up the relevant object from the handler?

There may be a way using bind(), but the idea was to make simple specialised
subclasses as needed that either invoke a method or take a function that can
be wrapped (something like command = functools.partial(command, self)).
The naming scheme doesn't hold up, but I'm pretty sure that's not what you
mean?

I meant that when you need other classes with an .id you will now have to
implement .id_string(), too. A simple approach like

entry = tkinter.Entry(...)
entry.id = 42

won't work anymore.

Peter
 
A

Alf P. Steinbach

* Gabriel Genellina:
I don't understand either. R1 and R2 have *different* semantics.

Assume that they have the very exact same semantics -- like two TV sets that
look the same and work the same except when you open 'em up and poke around in
there, oh holy cow, in this one there's stuff that isn't in the other.

After all the semantics (like the TV controls and their effects) were left
unspecified, only the internal representations (like, the main circuit boards
*inside* the TVs) were described, and the example only makes sense if R1 and R2
have the same semantics, that is, work the same via their public interfaces.

If I'd known that people would start a discussion based on their wishes that the
unspecied semantics should be some that made the example meaningless, well, then
I'd simply specified the semantics -- consider that done.

They don't behave the same.

Assume that they do -- except when you go poking into the innards.


Cheers & hth.,

- Alf
 
G

Gabriel Genellina

* Gabriel Genellina:

Assume that they have the very exact same semantics -- like two TV
sets that look the same and work the same except when you open 'em up
and poke around in there, oh holy cow, in this one there's stuff that
isn't in the other.

Assume that they do -- except when you go poking into the innards.

And the problem is...?
That the internal details are different? Who cares?
(I'm lost now.)
 
A

Alf P. Steinbach

* Gabriel Genellina:
And the problem is...?
That the internal details are different? Who cares?
(I'm lost now.)

It's a common Usenet phenomenon: the warping thread.

Context is lost.

It is available by going back up-thread but at the cost of some work. :)


Cheers & hth.,

- Alf
 
T

Terry Reedy

Alf said:
However, the natural semantics is that various logical properties, such
as left, top, right, bottom, width and height, can be varied independently.

But they *CANNOT* be varied independently. A rectangle with side
parallel to the axes has exactly 4 degress of freedom, not 6.

Terry Jan Reedy
 
A

Alf P. Steinbach

* Terry Reedy:
But they *CANNOT* be varied independently. A rectangle with side
parallel to the axes has exactly 4 degress of freedom, not 6.

Yes <g>. That's the basic idea of the example I presented up-thread, that's
discussed here. With R1's state variables width and heigh can be varied
independently by direct modification, with R2 it's right and bottom.

The public interface must also make this choice, but it's an independent choice:
the internal rectangle representation can have the opposite choice.

And conversely, that means that if the internal representation isn't used
directly, then it can be changed without affecting the public interface.


Cheers,

- Alf
 
S

Steven D'Aprano

* Gabriel Genellina:

Assume that they have the very exact same semantics


Why would we assume that when you have explicitly told us that they don't?

You stated categorically that they behave differently when you assign to
the attribute/property "top". According to your own description, setting
R1.top moves the rectangle, while setting R2.top resizes it. Perhaps the
difference between "move" and "resize" is too subtle for you, but you can
trust us on this, they are different semantics.

-- like two TV
sets that look the same and work the same except when you open 'em up
and poke around in there, oh holy cow, in this one there's stuff that
isn't in the other.


Whether "top" is an attribute or a property is irrelevant, it is still
part of the public API of the class. Such public attributes are NOT
private internal details, they are part of the public interface. You've
been told this repeatedly. Perhaps one more time may help:

Public attributes are public.
 
A

Alf P. Steinbach

* Steven D'Aprano:
Why would we assume that when you have explicitly told us that they don't?

You stated categorically that they behave differently when you assign to
the attribute/property "top".

Uh, severe reading difficulties ... referring to self in plural ... Hm. :)

But anyway, in the example description I wrote

"With R1 direct changes of left and top keeps the rectangle's size"

and this is in the context of a discussion of modifying data attributes directly
versus using properties.

Anyway, if that formulation was confusing I have clarified it later, so you
really, ideally, should have no problem grasping this.

According to your own description, setting
R1.top moves the rectangle, while setting R2.top resizes it. Perhaps the
difference between "move" and "resize" is too subtle for you, but you can
trust us on this, they are different semantics.

No, I would absolutely not trust you Steven, whether that's plural or singular,
to assign semantics to my examples.

Whether "top" is an attribute or a property is irrelevant,

Sorry, that's incorrect.

For example, if it is a read only property than you can't assign to the property.

For another example, if it is a read/write property than it can update any parts
of the rectangle represention.

it is still
part of the public API of the class.

Sorry, that's incorrect; it depends on the class.

Such public attributes are NOT
private internal details, they are part of the public interface.

Sorry, that's incorrect; it depends on the class, and as far as I know and have
been informed here there are no private attributes in Python, just a notational
convention.

You've
been told this repeatedly.

Sorry, but repeating what you want me to have meant in my example, contrary to
the direct text of the example, contrary to its context, choosing a meaningless
interpreteration of what's left when you have ignored the text, plus contrary to
further clarifications, well that's daft to say the least.

Perhaps one more time may help:

Public attributes are public.

It would be nice if Python had private ones, yes.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Steven D'Aprano:

Uh, severe reading difficulties ... referring to self in plural ... Hm. :)

But anyway, in the example description I wrote

"With R1 direct changes of left and top keeps the rectangle's size"

and this is in the context of a discussion of modifying data attributes
directly versus using properties.

Perhaps this makes it more clear: in R1, which has a width/height based
rectangle representation, assigning directly to the top data attribute
/effectively/ moves the rectangle vertically without changing its height, since
the height attribute is unchanged.

But that does not reflect any intended semantics, it's not a requirement; it's
an implementation artifact, a behavior that just results from direct
modification and the choice of a particular rectangle representation.

Real world Python example of that kind of artifact: as discussed in some other
thread here, doing open( ..., 'r+' ) followed by write followed directly by read
will on some implementations/systems produce garbage. Presumably because those
implementations use C "FILE*" to implement the functionality, and implements it
by a fairly direct mapping of calls down to the C level, where this sequence is
in general Undefined Behavior. You might regard it as semantics, and it's quite
real and presumably in a sense well-defined for the particular implementation on
the particular system, but it's not part of any intended semantics, and any who
relies on that behavior is doing it at other's risk.

For the R1 class the indended semantics, the specification that the programmer
was handed down or produced or had in mind, might include just rectangle
construction, checking intersection with other rectangle, and obtaining any of
three pairs of values: left upper corner, right lower corner and width+height.

For example. :)


Cheers & hth.,

- Alf
 
G

Gabriel Genellina

* Terry Reedy:

Yes <g>. That's the basic idea of the example I presented up-thread,
that's discussed here. With R1's state variables width and heigh can be
varied independently by direct modification, with R2 it's right and
bottom.

The public interface must also make this choice, but it's an independent
choice: the internal rectangle representation can have the opposite
choice.

And conversely, that means that if the internal representation isn't
used directly, then it can be changed without affecting the public
interface.

And that's exactly what everyone is saying - so we all agree then!
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top