Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

Tkinter callback arguments

 

 

First page Previous page 1 2 Next page Last page  View All Python python RSS feed   Index | Next | Previous | View Threaded


lord_eldritch at yahoo

Nov 1, 2009, 11:53 AM

Post #1 of 35 (722 views)
Permalink
Tkinter callback arguments

Hi

Maybe this is maybe something it has been answered somewhere but I haven't
been able to make it work. I wanna pass one variable to a callback function
and I've read the proper way is:

Button(......, command=lambda: function(x))

So with

def function(a): print a

I get the value of x. Ok. My problem now is that I generate the widgets in a
loop and I use the variable to 'label' the widget:

for x in range(0,3): Button(......, command=lambda: function(x))

so pressing each button should give me 0,1,2.

But with the lambda, I always get the last index, because it gets actualized
at each loop cycle. Is there any way to get that?

Thanks in advance!
--
Lord Eldritch
--
http://mail.python.org/mailman/listinfo/python-list


lord_eldritch at yahoo

Nov 1, 2009, 11:53 AM

Post #2 of 35 (707 views)
Permalink
Tkinter callback arguments [In reply to]

Hi

Maybe this is maybe something it has been answered somewhere but I haven't
been able to make it work. I wanna pass one variable to a callback function
and I've read the proper way is:

Button(......, command=lambda: function(x))

So with

def function(a): print a

I get the value of x. Ok. My problem now is that I generate the widgets in a
loop and I use the variable to 'label' the widget:

for x in range(0,3): Button(......, command=lambda: function(x))

so pressing each button should give me 0,1,2.

But with the lambda, I always get the last index, because it gets actualized
at each loop cycle. Is there any way to get that?

Thanks in advance!
--
Lord Eldritch
--
http://mail.python.org/mailman/listinfo/python-list


python at mrabarnett

Nov 1, 2009, 12:13 PM

Post #3 of 35 (712 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Lord Eldritch wrote:
> Hi
>
> Maybe this is maybe something it has been answered somewhere but I haven't
> been able to make it work. I wanna pass one variable to a callback function
> and I've read the proper way is:
>
> Button(......, command=lambda: function(x))
>
> So with
>
> def function(a): print a
>
> I get the value of x. Ok. My problem now is that I generate the widgets in a
> loop and I use the variable to 'label' the widget:
>
> for x in range(0,3): Button(......, command=lambda: function(x))
>
> so pressing each button should give me 0,1,2.
>
> But with the lambda, I always get the last index, because it gets actualized
> at each loop cycle. Is there any way to get that?
>
A lambda expression is just an unnamed function. At the point the
function is /called/ 'x' is bound to 3, so that's why 'function' is
always called with 3.

A function's default arguments are evaluated when the function is
/defined/, so you can save the current value of 'x' creating the
function (the lambda expression, in this case) with a default argument:

for x in range(0,3):
Button(......, command=lambda arg=x: function(arg))

The following will also work, although you might find the "x=x" a bit
surprising/confusing if you're not used to how Python works:

for x in range(0,3):
Button(......, command=lambda x=x: function(x))
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 1, 2009, 3:19 PM

Post #4 of 35 (704 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* MRAB:
> Lord Eldritch wrote:
>> Hi
>>
>> Maybe this is maybe something it has been answered somewhere but I
>> haven't been able to make it work. I wanna pass one variable to a
>> callback function and I've read the proper way is:
>>
>> Button(......, command=lambda: function(x))
>>
>> So with
>>
>> def function(a): print a
>>
>> I get the value of x. Ok. My problem now is that I generate the
>> widgets in a loop and I use the variable to 'label' the widget:
>>
>> for x in range(0,3): Button(......, command=lambda: function(x))
>>
>> so pressing each button should give me 0,1,2.
>>
>> But with the lambda, I always get the last index, because it gets
>> actualized at each loop cycle. Is there any way to get that?
>>
> A lambda expression is just an unnamed function. At the point the
> function is /called/ 'x' is bound to 3, so that's why 'function' is
> always called with 3.
>
> A function's default arguments are evaluated when the function is
> /defined/, so you can save the current value of 'x' creating the
> function (the lambda expression, in this case) with a default argument:
>
> for x in range(0,3):
> Button(......, command=lambda arg=x: function(arg))
>
> The following will also work, although you might find the "x=x" a bit
> surprising/confusing if you're not used to how Python works:
>
> for x in range(0,3):
> Button(......, command=lambda x=x: function(x))

An alternative reusable alternative is to create a button-with-id class.

This is my very first Python class so I'm guessing that there are all sorts of
issues, in particular naming conventions.

And the idea of creating a reusable solution for such a small issue may be
un-pythonic?

But just as an example, in Python 3.x,


<code>
import tkinter
# I guess for Python 2.x do "import Tkinter as tkinter" but haven't tested.


class IdButton( tkinter.Button ):
def __init__( self, owner_widget, id = None, command = None, **args ):
tkinter.Button.__init__(
self, owner_widget, args, command = self.__on_tk_command
)
self.__id = id
self.__specified_command = command

def __on_tk_command( self ):
if self.__specified_command != None:
self.__specified_command( self )
else:
self.on_clicked()

def on_clicked( self ):
pass
def id( self ):
return self.__id
def id_string( self ):
return str( self.id() );


def on_button_click( aButton ):
print( "Button " + aButton.id_string() + " clicked!" )

window = tkinter.Tk()

n_buttons = 3
for x in range( 1, n_buttons + 1 ):
IdButton(
window, id = x, text = "Button " + str( x ), command = on_button_click
).pack()

window.mainloop()
</code>


Cheers,

- Alf

PS: Now I see that I've used camelCase once. Oh well...
--
http://mail.python.org/mailman/listinfo/python-list


lord_eldritch at yahoo

Nov 1, 2009, 7:23 PM

Post #5 of 35 (695 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

> * MRAB:

Thank you all! It is working now nicely! God! I love usenet..:D
--
Lord Eldritch
--
http://mail.python.org/mailman/listinfo/python-list


eric.brunel.pragmadev at gmail

Nov 2, 2009, 1:07 AM

Post #6 of 35 (690 views)
Permalink
Re: Tkinter callback arguments [In reply to]

On Nov 1, 8:53 pm, Lord Eldritch <lord_eldri...@yahoo.co.uk> wrote:
> Hi
>
> Maybe this is maybe something it has been answered somewhere but I haven't
> been able to make it work. I wanna pass one variable to a callback function
> and I've read the proper way is:
>
> Button(......, command=lambda: function(x))
>
> So with
>
> def function(a): print a
>
> I get the value of x. Ok. My problem now is that I generate the widgets in a
> loop and I use the variable to 'label' the widget:
>
> for x in range(0,3): Button(......, command=lambda: function(x))
>
> so pressing each button should give me 0,1,2.
>
> But with the lambda, I always get the last index, because it gets actualized
> at each loop cycle. Is there any way to get that?

for x in range(0,3): Button(..., command=functools.partial(function,
x))

With the functools standard module that appeared in version 2.5, I
hardly ever use lambdas in Tkinter callbacks now.

> Thanks in advance!

HTH
--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Nov 2, 2009, 1:26 AM

Post #7 of 35 (692 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

>> for x in range(0,3):
>> Button(......, command=lambda x=x: function(x))
>
> An alternative reusable alternative is to create a button-with-id class.
>
> This is my very first Python class so I'm guessing that there are all
> sorts of issues, in particular naming conventions.

Pseudo-private attributes, javaesque getter methods, unidiomatic None-
checks, broken naming conventions (**args), spaces in funny places...

> And the idea of creating a reusable solution for such a small issue may be
> un-pythonic?

Screw pythonic, the signal/noise ratio is awful in any language.

> But just as an example, in Python 3.x,

...for achieving less in more lines?

> <code>
> import tkinter
> # I guess for Python 2.x do "import Tkinter as tkinter" but haven't
> # tested.
>
>
> class IdButton( tkinter.Button ):
> def __init__( self, owner_widget, id = None, command = None, **args
> ):
> tkinter.Button.__init__(
> self, owner_widget, args, command = self.__on_tk_command
> )
> self.__id = id
> self.__specified_command = command
>
> def __on_tk_command( self ):
> if self.__specified_command != None:
> self.__specified_command( self )
> else:
> self.on_clicked()
>
> def on_clicked( self ):
> pass
> def id( self ):
> return self.__id
> def id_string( self ):
> return str( self.id() );
>
>
> def on_button_click( aButton ):
> print( "Button " + aButton.id_string() + " clicked!" )
>
> window = tkinter.Tk()
>
> n_buttons = 3
> for x in range( 1, n_buttons + 1 ):
> IdButton(
> window, id = x, text = "Button " + str( x ), command =
> on_button_click ).pack()
>
> window.mainloop()
> </code>

I'm not grumpy, I just don't like your code ;) And I don't like the notion
that you are about to spread this style with your book...

Peter


--
http://mail.python.org/mailman/listinfo/python-list


Brian.Mingus at Colorado

Nov 2, 2009, 1:37 AM

Post #8 of 35 (693 views)
Permalink
Re: Tkinter callback arguments [In reply to]

On Mon, Nov 2, 2009 at 2:26 AM, Peter Otten <__peter__ [at] web> wrote:

> Alf P. Steinbach wrote:
>
> >> for x in range(0,3):
> >> Button(......, command=lambda x=x: function(x))
> >
> > An alternative reusable alternative is to create a button-with-id class.
> >
> > This is my very first Python class so I'm guessing that there are all
> > sorts of issues, in particular naming conventions.
>
> Pseudo-private attributes, javaesque getter methods, unidiomatic None-
> checks, broken naming conventions (**args), spaces in funny places...
>
> > And the idea of creating a reusable solution for such a small issue may
> be
> > un-pythonic?
>
> Screw pythonic, the signal/noise ratio is awful in any language.
>
> > But just as an example, in Python 3.x,
>
> ...for achieving less in more lines?
>
> > <code>
> > import tkinter
> > # I guess for Python 2.x do "import Tkinter as tkinter" but haven't
> > # tested.
> >
> >
> > class IdButton( tkinter.Button ):
> > def __init__( self, owner_widget, id = None, command = None, **args
> > ):
> > tkinter.Button.__init__(
> > self, owner_widget, args, command = self.__on_tk_command
> > )
> > self.__id = id
> > self.__specified_command = command
> >
> > def __on_tk_command( self ):
> > if self.__specified_command != None:
> > self.__specified_command( self )
> > else:
> > self.on_clicked()
> >
> > def on_clicked( self ):
> > pass
> > def id( self ):
> > return self.__id
> > def id_string( self ):
> > return str( self.id() );
> >
> >
> > def on_button_click( aButton ):
> > print( "Button " + aButton.id_string() + " clicked!" )
> >
> > window = tkinter.Tk()
> >
> > n_buttons = 3
> > for x in range( 1, n_buttons + 1 ):
> > IdButton(
> > window, id = x, text = "Button " + str( x ), command =
> > on_button_click ).pack()
> >
> > window.mainloop()
> > </code>
>
> I'm not grumpy, I just don't like your code ;) And I don't like the notion
> that you are about to spread this style with your book...
>
> Peter


I was going to agree with you (
particularly about this
)
but then I saw your __email address__ and realized that you, too, have no
style.


alfps at start

Nov 2, 2009, 2:37 AM

Post #9 of 35 (687 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Peter Otten:
> Alf P. Steinbach wrote:
>
>>> for x in range(0,3):
>>> Button(......, command=lambda x=x: function(x))
>> An alternative reusable alternative is to create a button-with-id class.
>>
>> This is my very first Python class so I'm guessing that there are all
>> sorts of issues, in particular naming conventions.
>
> Pseudo-private attributes

That means there is some way of making attributes private?

Probably that comes across as an inane question but I ask it anyway. I haven't
really started to look at Python classes. I'm guessing that by asking here I may
learn things that are not obvious from the documentation.


>, javaesque getter methods,

What do you mean by that?

What I associate with Java getter method is mainly the "get" prefix, for Java
introspection.


> unidiomatic None-checks

What's the idiomatic Python way for an optional thing?

In this case one alternative I see could be to get rid of the __on_tc_command
method and more directly tell tkinter.Button to call the relevant function,
doing the if-else choice once only in the IdButton constructor.

Is that what you mean?

I'm thinking more in terms of customization points when I write code.

So I tend to avoid hardcoding things internally in methods, instead designing
the choices out to where they're accessible to client code.


>, broken naming conventions (**args),

How to do this argument forwarding in modern style?

Or is there an alternative to argument forwarding for this example?


> spaces in funny places...

Bah. ;-)


>> And the idea of creating a reusable solution for such a small issue may be
>> un-pythonic?
>
> Screw pythonic, the signal/noise ratio is awful in any language.
>
>> But just as an example, in Python 3.x,
>
> ...for achieving less in more lines?

Now, that's a good Python-independent question! :-)

Re your question's the number of lines: /if/ the code is heavily reused then the
number of lines doesn't matter since they're only written /once/; the net effect
can even be to reduce the total number of lines, or at least the number of
apparent function points (or whatever size metric). That's part of what
"reusable" means. For example, if the OP used the code then he or she didn't
type them lines, but just copy/paste'd them, less work than typing in a lambda
definition in every button creation, and more clear code at every creation.

Re your question's what (the) reusability achieves.

First, when you and others have used such a thing in a number of places then you
gain confidence in correctness. For example, you don't wonder whether Python's
str type is correct, and when you test your program you don't test the str type
implementation. Since it's been used so much you know that it (mainly) is
correct, and that any remaining bug in there can't be all that serious, because
if it was then it would've surfaced in earlier use of the type.

This advantage of confidence in correctness can be realized even without heavy
reuse, because the encapsulation that's necessary for reuse, here having the
code in a class, also makes it possible with more centralized testing.

A centralized, encapsulated piece of code can be tested to death and deemed
correct (enough) and frozen, while the application of a code pattern in umpteen
places in umpteen programs, generally can't.

Second, when you do find a bug, or need more functionality, or whatever, there's
just /one place/ to fix/extend, whatever, instead of updating umpteen places in
umpteen programs, and trying to be sure that you've covered all instances and
done the right thing every place regardless of local variations (which is pretty
hopeless in general, but my experience with that kind of badness has mostly been
with C, not Python). More technically, it's reduced redundancy, in this case
avoiding redundant application of a code pattern everywhere one needs a button
with id (if that happens often). Reduced redundancy = good.

And third, as I mentioned, at every button creation, or in general every place
you'd use inline code rather than some reusable thing, you can get more clear
code, which can (but will not automatically :-) ) reduce maintainance time.

But, the big drawback. It's easy to become enamoured by reusability and invest a
lot of work in encapsulation and general reusability, since it has those three
big desirable traits. But when what one creates is not actually reused then most
of that work can be /wasted/... :-) For example, if the code only is used in 1
place, then the advantage of centralized testing is pretty moot unless that code
is changing for other reasons, for it doesn't matter much if you test it here or
there. It can be simpler to test it here, inline, than over there.

And another big drawback, but I believe it's less important in Python, that a
reusable thing can be less efficient because it can't take advantage of locally
available information and functionality each place where it's used, while inline
code that achieves the same (applying a pattern) can take advantage.


>> <code>
>> import tkinter
>> # I guess for Python 2.x do "import Tkinter as tkinter" but haven't
>> # tested.
>>
>>
>> class IdButton( tkinter.Button ):
>> def __init__( self, owner_widget, id = None, command = None, **args
>> ):
>> tkinter.Button.__init__(
>> self, owner_widget, args, command = self.__on_tk_command
>> )
>> self.__id = id
>> self.__specified_command = command
>>
>> def __on_tk_command( self ):
>> if self.__specified_command != None:
>> self.__specified_command( self )
>> else:
>> self.on_clicked()
>>
>> def on_clicked( self ):
>> pass
>> def id( self ):
>> return self.__id
>> def id_string( self ):
>> return str( self.id() );
>>
>>
>> def on_button_click( aButton ):
>> print( "Button " + aButton.id_string() + " clicked!" )
>>
>> window = tkinter.Tk()
>>
>> n_buttons = 3
>> for x in range( 1, n_buttons + 1 ):
>> IdButton(
>> window, id = x, text = "Button " + str( x ), command =
>> on_button_click ).pack()
>>
>> window.mainloop()
>> </code>
>
> I'm not grumpy, I just don't like your code ;) And I don't like the notion
> that you are about to spread this style with your book...

He he. :-) I've yet to acquire any Python style.


Cheers, & thanks,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Nov 2, 2009, 4:18 AM

Post #10 of 35 (682 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

> * Peter Otten:
>> Alf P. Steinbach wrote:
>>
>>>> for x in range(0,3):
>>>> Button(......, command=lambda x=x: function(x))
>>> An alternative reusable alternative is to create a button-with-id class.
>>>
>>> This is my very first Python class so I'm guessing that there are all
>>> sorts of issues, in particular naming conventions.
>>
>> Pseudo-private attributes
>
> That means there is some way of making attributes private?

No, there isn't. And the name mangled __attribute is hardly ever needed. Use
_attribute to convey the message "If you mess with this attribute you're on
your own".

> Probably that comes across as an inane question but I ask it anyway. I
> haven't really started to look at Python classes. I'm guessing that by
> asking here I may learn things that are not obvious from the
> documentation.
>
>
>>, javaesque getter methods,
>
> What do you mean by that?

In Java you have a private attribute and a public getter method. In Python
you can just make the attribute public, i. e.

# bad
class A:
def __init__(self):
self._id = 42
def id(self): return self._id

# good
class A:
def __init__(self):
self.id = 42

You can always switch to

class A: # assuming 3.x
@property
def id(self):
id = arbitrary_code()
return id

later.

> What I associate with Java getter method is mainly the "get" prefix, for
> Java introspection.
>
>
>> unidiomatic None-checks
>
> What's the idiomatic Python way for an optional thing?

if some_value is None: ...

> In this case one alternative I see could be to get rid of the
> __on_tc_command method and more directly tell tkinter.Button to call the
> relevant function, doing the if-else choice once only in the IdButton
> constructor.
>
> Is that what you mean?
>
> I'm thinking more in terms of customization points when I write code.
>
> So I tend to avoid hardcoding things internally in methods, instead
> designing the choices out to where they're accessible to client code.
>
>
>>, broken naming conventions (**args),
>
> How to do this argument forwarding in modern style?

I meant that keyword args are traditionally named kw or kwargs, the name
"args" is normally used for positional arguments:

def f(*args, **kw):
"whatever"

> Or is there an alternative to argument forwarding for this example?
>
>
>> spaces in funny places...
>
> Bah. ;-)
>
>
>>> And the idea of creating a reusable solution for such a small issue may
>>> be un-pythonic?
>>
>> Screw pythonic, the signal/noise ratio is awful in any language.
>>
>>> But just as an example, in Python 3.x,
>>
>> ...for achieving less in more lines?
>
> Now, that's a good Python-independent question! :-)
>
> Re your question's the number of lines: /if/ the code is heavily reused
> then the number of lines doesn't matter since they're only written /once/;

Every time someone has to read the code he will read, hesitate, read again,
and then hopefully come to the conclusion that the code does nothing,
consider not using it, or if it is not tied into a larger project removing
it.

> the net effect can even be to reduce the total number of lines, or at
> least the number of apparent function points (or whatever size metric).
> That's part of what "reusable" means. For example, if the OP used the code
> then he or she didn't type them lines, but just copy/paste'd them, less
> work than typing in a lambda definition in every button creation, and more
> clear code at every creation.

But most of your code does *nothing*.

> Re your question's what (the) reusability achieves.
>
> First, when you and others have used such a thing in a number of places
> then you gain confidence in correctness. For example, you don't wonder
> whether Python's str type is correct, and when you test your program you
> don't test the str type implementation. Since it's been used so much you
> know that it (mainly) is correct, and that any remaining bug in there
> can't be all that serious, because if it was then it would've surfaced in
> earlier use of the type.

The theory may be OK, but in practice it doesn't always work out. Example:
Why do you introduce button.id_string() instead of str(button.id)? The
programmer will hesitate, wonder whether to use button.id() or
button.id_string(), how the two may interconnect...
It feels more like a hoop to jump through than a helpful service providing
tried an tested code.

> This advantage of confidence in correctness can be realized even without
> heavy reuse, because the encapsulation that's necessary for reuse, here
> having the code in a class, also makes it possible with more centralized
> testing.

Was this sentence/paragraph produced by http://pdos.csail.mit.edu/scigen/ ?

> A centralized, encapsulated piece of code can be tested to death and
> deemed correct (enough) and frozen, while the application of a code
> pattern in umpteen places in umpteen programs, generally can't.

I'd like to see a good test suite for your IdButton class, especially how it
copes with the design decision that you can override the on_clicked() stub,
or provide a command function, or both.

> Second, when you do find a bug, or need more functionality, or whatever,
> there's just /one place/ to fix/extend, whatever, instead of updating
> umpteen places in umpteen programs, and trying to be sure that you've
> covered all instances and done the right thing every place regardless of
> local variations (which is pretty hopeless in general, but my experience
> with that kind of badness has mostly been with C, not Python). More
> technically, it's reduced redundancy, in this case avoiding redundant
> application of a code pattern everywhere one needs a button with id (if
> that happens often). Reduced redundancy = good.

I agree with that maxim. Incidentally I have just found a nice example of
redundancy for you:

>>> def __on_tk_command( self ):
>>> if self.__specified_command != None:
>>> self.__specified_command( self )
>>> else:
>>> self.on_clicked()

Peter

--
http://mail.python.org/mailman/listinfo/python-list


deets at nospam

Nov 2, 2009, 5:07 AM

Post #11 of 35 (689 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

> * Peter Otten:
>> Alf P. Steinbach wrote:
>>
>>>> for x in range(0,3):
>>>> Button(......, command=lambda x=x: function(x))
>>> An alternative reusable alternative is to create a button-with-id class.
>>>
>>> This is my very first Python class so I'm guessing that there are all
>>> sorts of issues, in particular naming conventions.
>>
>> Pseudo-private attributes
>
> That means there is some way of making attributes private?

No, it means that in Python we are consenting adults, and either respect
attributes with a leading underscore as private - or willfully chose to
*not* do that because of good reasons.

And the double-underscore is used against name-clashes, not for
enhanced "privacy".

>>, javaesque getter methods,
>
> What do you mean by that?
>
> What I associate with Java getter method is mainly the "get" prefix, for
> Java introspection.

You have an attribute id, whatfor do you need a method id? If at some point
this id becomes a computed value - you introduce a property

And that's what Peter meant with "javanesque" - the exact reason why in java
everything is wrapped in getters/setters is that the language lacks a
property-mechanism, so to present a consistent interface over several
iterations of the code, one has to introduce them for every single
attribute - regardless of their future destiny.

>
>> unidiomatic None-checks
>
> What's the idiomatic Python way for an optional thing?

None is a singleton, so the idiomatic check is for object identity:

foo = None
foo is None


Diez
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 2, 2009, 5:54 AM

Post #12 of 35 (683 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Peter Otten:
> Alf P. Steinbach wrote:
>
>> * Peter Otten:
>>> Alf P. Steinbach wrote:
>>>
>>>>> for x in range(0,3):
>>>>> Button(......, command=lambda x=x: function(x))
>>>> An alternative reusable alternative is to create a button-with-id class.
>>>>
>>>> This is my very first Python class so I'm guessing that there are all
>>>> sorts of issues, in particular naming conventions.
>>> Pseudo-private attributes
>> That means there is some way of making attributes private?
>
> No, there isn't. And the name mangled __attribute is hardly ever needed. Use
> _attribute to convey the message "If you mess with this attribute you're on
> your own".

Thanks!


>> Probably that comes across as an inane question but I ask it anyway. I
>> haven't really started to look at Python classes. I'm guessing that by
>> asking here I may learn things that are not obvious from the
>> documentation.
>>
>>
>>> , javaesque getter methods,
>> What do you mean by that?
>
> In Java you have a private attribute and a public getter method. In Python
> you can just make the attribute public, i. e.
>
> # bad
> class A:
> def __init__(self):
> self._id = 42
> def id(self): return self._id
>
> # good
> class A:
> def __init__(self):
> self.id = 42

I think I get the gist that locally saving lines of code, and generally avoiding
having to write empty argument list parentheses, and thereby also indicating in
a way that one is accessing a logical data attribute, is considered good in
Python, which goes to initial development time and the amount of code that one
must scan to grok it both for definition and usage -- is that correct?

But the trade-off is inviting modification of a supposedly fixed id, which goes
to correctness and later fix-it time?


> You can always switch to
>
> class A: # assuming 3.x
> @property
> def id(self):
> id = arbitrary_code()
> return id
>
> later.

Thanks, now I learned about @property... :-)

But when the thing has been used it's much more difficult to restrict the
functionality (making read-only, breaking code that changes id) than to add
functionality (making also writeable, breaking none of existing code).

So isn't "later" a bit late to make it read-only, shouldn't that be the initial
design, and then possibly adding a setter later if id's turn out to not be so
constant after all?


>> What I associate with Java getter method is mainly the "get" prefix, for
>> Java introspection.
>>
>>
>>> unidiomatic None-checks
>> What's the idiomatic Python way for an optional thing?
>
> if some_value is None: ...

Thanks!

But why is this preferred?


>> In this case one alternative I see could be to get rid of the
>> __on_tc_command method and more directly tell tkinter.Button to call the
>> relevant function, doing the if-else choice once only in the IdButton
>> constructor.
>>
>> Is that what you mean?
>>
>> I'm thinking more in terms of customization points when I write code.
>>
>> So I tend to avoid hardcoding things internally in methods, instead
>> designing the choices out to where they're accessible to client code.
>>
>>
>>> , broken naming conventions (**args),
>> How to do this argument forwarding in modern style?
>
> I meant that keyword args are traditionally named kw or kwargs, the name
> "args" is normally used for positional arguments:
>
> def f(*args, **kw):
> "whatever"

Thanks!

*Note to myself*: check if there are more such conventions.


>> Or is there an alternative to argument forwarding for this example?
>>
>>
>>> spaces in funny places...
>> Bah. ;-)
>>
>>
>>>> And the idea of creating a reusable solution for such a small issue may
>>>> be un-pythonic?
>>> Screw pythonic, the signal/noise ratio is awful in any language.
>>>
>>>> But just as an example, in Python 3.x,
>>> ...for achieving less in more lines?
>> Now, that's a good Python-independent question! :-)
>>
>> Re your question's the number of lines: /if/ the code is heavily reused
>> then the number of lines doesn't matter since they're only written /once/;
>
> Every time someone has to read the code he will read, hesitate, read again,
> and then hopefully come to the conclusion that the code does nothing,
> consider not using it, or if it is not tied into a larger project removing
> it.

I don't understand what you mean.

Not that it's a shiny example of code that does a lot, but it (1) simplifies and
shortens creation of buttons with id, and (2) provides a nice start for adding
other customizations of those buttons, and (3) supports searching for a button
with given command id, e.g. for purpose of hiding or enable/disable.

If I didn't just want to try out writing a Python class, which I've never done
before so it appeared interesting, I'd probably just skipped points 2 and 3 and
written the same functionality as a factory function, like


<code>
import tkinter

def id_button( owner_widget, id, command = None, **kwargs ):
def tk_command( an_id = id, a_command = command ):
if a_command is not None: a_command( id )
return tkinter.Button( owner_widget, kwargs, command = tk_command )

def on_button_click( id ):
print( "Button " + str( id ) + " clicked!" )

window = tkinter.Tk()

n_buttons = 3
for x in range( 1, n_buttons + 1 ):
id_button(
window, id = x, text = "Button " + str( x ), command = on_button_click
).pack()

window.mainloop()
</code>


but once you have the class, for whatever reason, it would be silly not to use
it, especially since it provides points 2 and 3 which the function doesn't.

By the way, I as yet know next to *nothing* about binding of variable references
within a function such as tk_command above. Probably I've done Unnecessary
Things(TM) above?


>> the net effect can even be to reduce the total number of lines, or at
>> least the number of apparent function points (or whatever size metric).
>> That's part of what "reusable" means. For example, if the OP used the code
>> then he or she didn't type them lines, but just copy/paste'd them, less
>> work than typing in a lambda definition in every button creation, and more
>> clear code at every creation.
>
> But most of your code does *nothing*.

See above, points 2 and 3. Most of that class has to do with 2, customization
ability.


>> Re your question's what (the) reusability achieves.
>>
>> First, when you and others have used such a thing in a number of places
>> then you gain confidence in correctness. For example, you don't wonder
>> whether Python's str type is correct, and when you test your program you
>> don't test the str type implementation. Since it's been used so much you
>> know that it (mainly) is correct, and that any remaining bug in there
>> can't be all that serious, because if it was then it would've surfaced in
>> earlier use of the type.
>
> The theory may be OK, but in practice it doesn't always work out. Example:
> Why do you introduce button.id_string() instead of str(button.id)?

Because the string representation of an id then /can/ be customized
independently of the id. For example, id's might be integers but for string
representation you might want symbolic action names (e.g., you might have two or
more buttons with same title but different actions, so that title would be
ungood to identify button). And for another example, when debugging or testing
you might want the string represention of an id to provide more information
about the button and/or its context, and then id_string provides a single
central customization point -- provided it's used, of course. <g>


> The
> programmer will hesitate, wonder whether to use button.id() or
> button.id_string(), how the two may interconnect...

Hm, see immediately above.

It's perhaps a different way of thinking?


> It feels more like a hoop to jump through than a helpful service providing
> tried an tested code.

Yes.

It's the old "every computer science problem can be solved by adding an extra
layer of indirection".

Sometimes it's nice when you can do that centrally. Retrofitting the indirection
to existing client code can be hard.


>> This advantage of confidence in correctness can be realized even without
>> heavy reuse, because the encapsulation that's necessary for reuse, here
>> having the code in a class, also makes it possible with more centralized
>> testing.
>
> Was this sentence/paragraph produced by http://pdos.csail.mit.edu/scigen/ ?

No. :-) But you're right that testing isn't that much of an issue for that
class. If that's what you meant.


>> A centralized, encapsulated piece of code can be tested to death and
>> deemed correct (enough) and frozen, while the application of a code
>> pattern in umpteen places in umpteen programs, generally can't.
>
> I'd like to see a good test suite for your IdButton class, especially how it
> copes with the design decision that you can override the on_clicked() stub,
> or provide a command function, or both.

The design is that for any given IdButton there's a single point of
responsibility for the click action, namely either a button creation code
supplies that action, or it relies on the action defined in the class.

I.e. again customization ability, that the button creation code can /override/
the class provided action, per button, without getting into general overriding
of class methods, just by defining a nice little lambda inline in the call.

But as I learn more Python I may perhaps find that overriding class methods can
also be done that conveniently -- I don't know, keep in mind I'm a Python
newbie, and doing Very Much Else than studying Python. :-)


>> Second, when you do find a bug, or need more functionality, or whatever,
>> there's just /one place/ to fix/extend, whatever, instead of updating
>> umpteen places in umpteen programs, and trying to be sure that you've
>> covered all instances and done the right thing every place regardless of
>> local variations (which is pretty hopeless in general, but my experience
>> with that kind of badness has mostly been with C, not Python). More
>> technically, it's reduced redundancy, in this case avoiding redundant
>> application of a code pattern everywhere one needs a button with id (if
>> that happens often). Reduced redundancy = good.
>
> I agree with that maxim. Incidentally I have just found a nice example of
> redundancy for you:
>
>>>> def __on_tk_command( self ):
>>>> if self.__specified_command != None:
>>>> self.__specified_command( self )
>>>> else:
>>>> self.on_clicked()
>

Uh, could you expand on how that's redundant and how to make it less so?


Cheers, & thanks,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 2, 2009, 6:12 AM

Post #13 of 35 (685 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Diez B. Roggisch:
> Alf P. Steinbach wrote:
>
>> * Peter Otten:
>>> Alf P. Steinbach wrote:
>>>
>>>>> for x in range(0,3):
>>>>> Button(......, command=lambda x=x: function(x))
>>>> An alternative reusable alternative is to create a button-with-id class.
>>>>
>>>> This is my very first Python class so I'm guessing that there are all
>>>> sorts of issues, in particular naming conventions.
>>> Pseudo-private attributes
>> That means there is some way of making attributes private?
>
> No, it means that in Python we are consenting adults, and either respect
> attributes with a leading underscore as private - or willfully chose to
> *not* do that because of good reasons.

Hm. But thanks! That's very useful information -- now I'll not be going on a
wild goose chase!


> And the double-underscore is used against name-clashes, not for
> enhanced "privacy".
>
>>> , javaesque getter methods,
>> What do you mean by that?
>>
>> What I associate with Java getter method is mainly the "get" prefix, for
>> Java introspection.
>
> You have an attribute id, whatfor do you need a method id? If at some point
> this id becomes a computed value - you introduce a property
>
> And that's what Peter meant with "javanesque" - the exact reason why in java
> everything is wrapped in getters/setters is that the language lacks a
> property-mechanism, so to present a consistent interface over several
> iterations of the code, one has to introduce them for every single
> attribute - regardless of their future destiny.

Thanks again for useful information.

Also Peter mentioned this about changing simple attributes into properties at
later time, so that seems to at least not be unheard of in Python?

Your comment about "computed" makes it more clear what that's all about. Also
Bertrand Meyer (Eiffel language creator) had idea like that, he called it
"referential transparency". But I think when Python has this nice property
mechanism, why do people change direct data attributes into properties and not
the other way around or not at all, I mean using only properties for logical
data attributes -- e.g. assuring correctness first via read-only property?


>>> unidiomatic None-checks
>> What's the idiomatic Python way for an optional thing?
>
> None is a singleton, so the idiomatic check is for object identity:
>
> foo = None
> foo is None

Again, thanks, that helps me understand the rationale. Although not completely.
But there is a connection...


Cheers,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


deets at nospam

Nov 2, 2009, 6:18 AM

Post #14 of 35 (648 views)
Permalink
Re: Tkinter callback arguments [In reply to]

> Your comment about "computed" makes it more clear what that's all about.
> Also Bertrand Meyer (Eiffel language creator) had idea like that, he
> called it "referential transparency". But I think when Python has this
> nice property mechanism, why do people change direct data attributes into
> properties and not the other way around or not at all, I mean using only
> properties for logical
> data attributes -- e.g. assuring correctness first via read-only
> property?

I fail to see where read-only-ness of an attribute is a priori more correct
than having modifyable attributes. Again, it's an assumption of a future
use or constraint that is most of the times simply not correct or
relevant - at the price for more typing, and computational overhead.

Diez
--
http://mail.python.org/mailman/listinfo/python-list


mwilson at the-wire

Nov 2, 2009, 7:46 AM

Post #15 of 35 (684 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:
> * Peter Otten:
>> Alf P. Steinbach wrote:
>>> * Peter Otten:
>>>> unidiomatic None-checks
>>> What's the idiomatic Python way for an optional thing?
>>
>> if some_value is None: ...
>
> Thanks!
>
> But why is this preferred?

I guess because `some_value == None` restricts your choices if you want to
give some_value's usual class an __eq__ method. It's a pretty arcane
point.. but perhaps not.. the object named "some_value" might belong to a
class that expects its instances only to be compared with each other, for
the sake of economy and clear code.

Mel.


--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 2, 2009, 7:51 AM

Post #16 of 35 (689 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Diez B. Roggisch:
>> Your comment about "computed" makes it more clear what that's all about.
>> Also Bertrand Meyer (Eiffel language creator) had idea like that, he
>> called it "referential transparency". But I think when Python has this
>> nice property mechanism, why do people change direct data attributes into
>> properties and not the other way around or not at all, I mean using only
>> properties for logical
>> data attributes -- e.g. assuring correctness first via read-only
>> property?
>
> I fail to see where read-only-ness of an attribute is a priori more correct
> than having modifyable attributes.

No, I didn't mean that it is more correct to have an attribute as read-only. I
meant that letting a logical data attribute start out as a read only property
can help to ensure correctness. 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.


> Again, it's an assumption of a future
> use or constraint that is most of the times simply not correct or
> relevant - at the price for more typing, and computational overhead.

Hm, not sure.


Cheers,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


mwilson at the-wire

Nov 2, 2009, 8:19 AM

Post #17 of 35 (692 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:
> Your comment about "computed" makes it more clear what that's all about.
> Also Bertrand Meyer (Eiffel language creator) had idea like that, he
> called it "referential transparency". But I think when Python has this
> nice property mechanism, why do people change direct data attributes into
> properties and not the other way around or not at all,

Python tends to prefer simple forms over complicated forms, so having a
programmer write

x = something.that

and implementing a getter inside the call to something.__getattr__ is better
than

x = something.that()

with a pair of needless parens, and then mangling the compiler/runtime to
suddenly use the value of `that`, uncalled, if `something` happens to be an
instance of the class we're discussing.

Note too that

something.that = x

is pretty clean, but

something.that() = x

can't be done at all, and the syntactically correct

something.that(x)

just doesn't look like the simple assignment statement.

Mel.


--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Nov 2, 2009, 9:09 AM

Post #18 of 35 (692 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

> * Peter Otten:
>> Alf P. Steinbach wrote:
>>
>>> * Peter Otten:
>>>> Alf P. Steinbach wrote:
>>>>
>>>>>> for x in range(0,3):
>>>>>> Button(......, command=lambda x=x: function(x))
>>>>> An alternative reusable alternative is to create a button-with-id
>>>>> class.
>>>>>
>>>>> This is my very first Python class so I'm guessing that there are all
>>>>> sorts of issues, in particular naming conventions.
>>>> Pseudo-private attributes
>>> That means there is some way of making attributes private?
>>
>> No, there isn't. And the name mangled __attribute is hardly ever needed.
>> Use _attribute to convey the message "If you mess with this attribute
>> you're on your own".
>
> Thanks!
>
>
>>> Probably that comes across as an inane question but I ask it anyway. I
>>> haven't really started to look at Python classes. I'm guessing that by
>>> asking here I may learn things that are not obvious from the
>>> documentation.
>>>
>>>
>>>> , javaesque getter methods,
>>> What do you mean by that?
>>
>> In Java you have a private attribute and a public getter method. In
>> Python you can just make the attribute public, i. e.
>>
>> # bad
>> class A:
>> def __init__(self):
>> self._id = 42
>> def id(self): return self._id
>>
>> # good
>> class A:
>> def __init__(self):
>> self.id = 42
>
> I think I get the gist that locally saving lines of code, and generally
> avoiding having to write empty argument list parentheses, and thereby also
> indicating in a way that one is accessing a logical data attribute, is
> considered good in Python, which goes to initial development time and the
> amount of code that one
> must scan to grok it both for definition and usage -- is that correct?

Remember that .id does contain static data in your case. If it were a
lengthy calculation the .id() method would be OK.

> But the trade-off is inviting modification of a supposedly fixed id, which
> goes to correctness and later fix-it time?
>
>
>> You can always switch to
>>
>> class A: # assuming 3.x
>> @property
>> def id(self):
>> id = arbitrary_code()
>> return id
>>
>> later.
>
> Thanks, now I learned about @property... :-)
>
> But when the thing has been used it's much more difficult to restrict the
> functionality (making read-only, breaking code that changes id) than to
> add functionality (making also writeable, breaking none of existing code).
>
> So isn't "later" a bit late to make it read-only, shouldn't that be the
> initial design, and then possibly adding a setter later if id's turn out
> to not be so constant after all?

You can break existing code with changes in a library in so many ways that I
don't think this specific problem matters much. But if you don't feel
comfortable with writing a warning into the documentation use a getter
function or a property.

>>> What I associate with Java getter method is mainly the "get" prefix, for
>>> Java introspection.
>>>
>>>
>>>> unidiomatic None-checks
>>> What's the idiomatic Python way for an optional thing?
>>
>> if some_value is None: ...
>
> Thanks!
>
> But why is this preferred?
>
>
>>> In this case one alternative I see could be to get rid of the
>>> __on_tc_command method and more directly tell tkinter.Button to call the
>>> relevant function, doing the if-else choice once only in the IdButton
>>> constructor.
>>>
>>> Is that what you mean?
>>>
>>> I'm thinking more in terms of customization points when I write code.
>>>
>>> So I tend to avoid hardcoding things internally in methods, instead
>>> designing the choices out to where they're accessible to client code.
>>>
>>>
>>>> , broken naming conventions (**args),
>>> How to do this argument forwarding in modern style?
>>
>> I meant that keyword args are traditionally named kw or kwargs, the name
>> "args" is normally used for positional arguments:
>>
>> def f(*args, **kw):
>> "whatever"
>
> Thanks!
>
> *Note to myself*: check if there are more such conventions.
>
>
>>> Or is there an alternative to argument forwarding for this example?
>>>
>>>
>>>> spaces in funny places...
>>> Bah. ;-)
>>>
>>>
>>>>> And the idea of creating a reusable solution for such a small issue
>>>>> may be un-pythonic?
>>>> Screw pythonic, the signal/noise ratio is awful in any language.
>>>>
>>>>> But just as an example, in Python 3.x,
>>>> ...for achieving less in more lines?
>>> Now, that's a good Python-independent question! :-)
>>>
>>> Re your question's the number of lines: /if/ the code is heavily reused
>>> then the number of lines doesn't matter since they're only written
>>> /once/;
>>
>> Every time someone has to read the code he will read, hesitate, read
>> again, and then hopefully come to the conclusion that the code does
>> nothing, consider not using it, or if it is not tied into a larger
>> project removing it.
>
> I don't understand what you mean.

Writing code is not fire and forget. It has to be debugged, tested,
maintained, and will be read quite a few times in the process. Therefore it
is important that you make it easy to read and understand.

> Not that it's a shiny example of code that does a lot, but it (1)
> simplifies and shortens creation of buttons with id, and (2) provides a
> nice start for adding other customizations of those buttons, and (3)
> supports searching for a button with given command id, e.g. for purpose of
> hiding or enable/disable.
>
> If I didn't just want to try out writing a Python class, which I've never
> done before so it appeared interesting, I'd probably just skipped points 2
> and 3 and written the same functionality as a factory function, like
>
>
> <code>
> import tkinter
>
> def id_button( owner_widget, id, command = None, **kwargs ):
> def tk_command( an_id = id, a_command = command ):
> if a_command is not None: a_command( id )
> return tkinter.Button( owner_widget, kwargs, command = tk_command )
>
> def on_button_click( id ):
> print( "Button " + str( id ) + " clicked!" )
>
> window = tkinter.Tk()
>
> n_buttons = 3
> for x in range( 1, n_buttons + 1 ):
> id_button(
> window, id = x, text = "Button " + str( x ), command =
> on_button_click ).pack()
>
> window.mainloop()
> </code>

I prefer that one, though without extra spaces in funny places.

> but once you have the class, for whatever reason, it would be silly not to
> use it, especially since it provides points 2 and 3 which the function
> doesn't.
>
> By the way, I as yet know next to *nothing* about binding of variable
> references within a function such as tk_command above. Probably I've done
> Unnecessary Things(TM) above?

Nothing too obvious; you could avoid the noop tk_command, and maybe provide
the button instead of the id (all code untested):

def make_button(owner, id, command=None, **kwargs):
button = tkinter.Button(owner, kwargs)
button.id = id
if command is not None:
button["command"] = functools.partial(command, button)
button.pack()

def button_click(button):
print(button["text"], "clicked!")

>>> the net effect can even be to reduce the total number of lines, or at
>>> least the number of apparent function points (or whatever size metric).
>>> That's part of what "reusable" means. For example, if the OP used the
>>> code then he or she didn't type them lines, but just copy/paste'd them,
>>> less work than typing in a lambda definition in every button creation,
>>> and more clear code at every creation.
>>
>> But most of your code does *nothing*.
>
> See above, points 2 and 3. Most of that class has to do with 2,
> customization ability.

Couldn't

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

be customised as easily?

>>> Re your question's what (the) reusability achieves.
>>>
>>> First, when you and others have used such a thing in a number of places
>>> then you gain confidence in correctness. For example, you don't wonder
>>> whether Python's str type is correct, and when you test your program you
>>> don't test the str type implementation. Since it's been used so much you
>>> know that it (mainly) is correct, and that any remaining bug in there
>>> can't be all that serious, because if it was then it would've surfaced
>>> in earlier use of the type.
>>
>> The theory may be OK, but in practice it doesn't always work out.
>> Example: Why do you introduce button.id_string() instead of
>> str(button.id)?
>
> Because the string representation of an id then /can/ be customized
> independently of the id. For example, id's might be integers but for
> string representation you might want symbolic action names (e.g., you
> might have two or more buttons with same title but different actions, so
> that title would be ungood to identify button). And for another example,
> when debugging or testing you might want the string represention of an id
> to provide more information about the button and/or its context, and then
> id_string provides a single
> central customization point -- provided it's used, of course. <g>

And what about the IdEntry class? To me it would make more sense to
customize the type of the .id value.

>> The
>> programmer will hesitate, wonder whether to use button.id() or
>> button.id_string(), how the two may interconnect...
>
> Hm, see immediately above.
>
> It's perhaps a different way of thinking?
>
>
>> It feels more like a hoop to jump through than a helpful service
>> providing tried an tested code.
>
> Yes.
>
> It's the old "every computer science problem can be solved by adding an
> extra layer of indirection".
>
> Sometimes it's nice when you can do that centrally. Retrofitting the
> indirection to existing client code can be hard.

Again, just-in-case indirections come at a cost. You are probably right
about the way of thinking.

>>> This advantage of confidence in correctness can be realized even without
>>> heavy reuse, because the encapsulation that's necessary for reuse, here
>>> having the code in a class, also makes it possible with more centralized
>>> testing.
>>
>> Was this sentence/paragraph produced by http://pdos.csail.mit.edu/scigen/
>> ?
>
> No. :-) But you're right that testing isn't that much of an issue for
> that class. If that's what you meant.

I read it twice but didn't understand it. You probably misplaced a word, but
I can't figure out which one.

>>> A centralized, encapsulated piece of code can be tested to death and
>>> deemed correct (enough) and frozen, while the application of a code
>>> pattern in umpteen places in umpteen programs, generally can't.
>>
>> I'd like to see a good test suite for your IdButton class, especially how
>> it copes with the design decision that you can override the on_clicked()
>> stub, or provide a command function, or both.
>
> The design is that for any given IdButton there's a single point of
> responsibility for the click action, namely either a button creation code
> supplies that action, or it relies on the action defined in the class.
>
> I.e. again customization ability, that the button creation code can
> /override/ the class provided action, per button, without getting into
> general overriding of class methods, just by defining a nice little lambda
> inline in the call.
>
> But as I learn more Python I may perhaps find that overriding class
> methods can
> also be done that conveniently -- I don't know, keep in mind I'm a
> Python newbie, and doing Very Much Else than studying Python. :-)
>
>
>>> Second, when you do find a bug, or need more functionality, or whatever,
>>> there's just /one place/ to fix/extend, whatever, instead of updating
>>> umpteen places in umpteen programs, and trying to be sure that you've
>>> covered all instances and done the right thing every place regardless of
>>> local variations (which is pretty hopeless in general, but my experience
>>> with that kind of badness has mostly been with C, not Python). More
>>> technically, it's reduced redundancy, in this case avoiding redundant
>>> application of a code pattern everywhere one needs a button with id (if
>>> that happens often). Reduced redundancy = good.
>>
>> I agree with that maxim. Incidentally I have just found a nice example of
>> redundancy for you:
>>
>>>>> def __on_tk_command( self ):
>>>>> if self.__specified_command != None:
>>>>> self.__specified_command( self )
>>>>> else:
>>>>> self.on_clicked()
>>
>
> Uh, could you expand on how that's redundant and how to make it less so?

How about

class IdButton(tkinter.Button):
def __init__(self, owner, id, command=None, **kwargs):
tkinter.Button.__init__(
self, owner, kwargs, command=self.on_clicked)
self.id = id
self.specified_command = command

def on_clicked(self):
if self.specified_command is not None:
self.specified_command(self)

Peter

--
http://mail.python.org/mailman/listinfo/python-list


deets at nospam

Nov 2, 2009, 2:16 PM

Post #19 of 35 (677 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach schrieb:
> * Diez B. Roggisch:
>>> Your comment about "computed" makes it more clear what that's all about.
>>> Also Bertrand Meyer (Eiffel language creator) had idea like that, he
>>> called it "referential transparency". But I think when Python has this
>>> nice property mechanism, why do people change direct data attributes
>>> into
>>> properties and not the other way around or not at all, I mean using only
>>> properties for logical
>>> data attributes -- e.g. assuring correctness first via read-only
>>> property?
>>
>> I fail to see where read-only-ness of an attribute is a priori more
>> correct
>> than having modifyable attributes.
>
> No, I didn't mean that it is more correct to have an attribute as
> read-only. I meant that letting a logical data attribute start out as a
> read only property can help to ensure correctness.

Which is the same thing said with other words.


> 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 - if you
change semantics of something, code might break. In Python, attributes
are part of the public interface as long as you don't explicitly define
them otherwise.

But preliminary assumptions about what could be in some yet unseen
future is introducing more code with more chances of errors, reducing
the flexibility at the same time. I still fail to see where that's good.

Code for what you need code for. It works - in all languages, but
especially in Python.

Diez
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 2, 2009, 4:18 PM

Post #20 of 35 (670 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Peter Otten:
> * Alf P. Steinbach wrote:
>> * Peter Otten:
>>> Every time someone has to read the code he will read, hesitate, read
>>> again, and then hopefully come to the conclusion that the code does
>>> nothing, consider not using it, or if it is not tied into a larger
>>> project removing it.
>> I don't understand what you mean.
>
> Writing code is not fire and forget. It has to be debugged, tested,
> maintained, and will be read quite a few times in the process. Therefore it
> is important that you make it easy to read and understand.

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


[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?

But AFAIK it's not (I got no arguments supplied in the calls when I tested,
although I don't know whether there are any options or whatever to make it
supply an event object argument, say).

And so AFAICS with this code there's no way to get an id in the on-click
(tkinter 'command') handler.


[snip]
>>> Example: Why do you introduce button.id_string() instead of
>>> str(button.id)?
>> Because the string representation of an id then /can/ be customized
>> independently of the id. For example, id's might be integers but for
>> string representation you might want symbolic action names (e.g., you
>> might have two or more buttons with same title but different actions, so
>> that title would be ungood to identify button). And for another example,
>> when debugging or testing you might want the string represention of an id
>> to provide more information about the button and/or its context, and then
>> id_string provides a single
>> central customization point -- provided it's used, of course. <g>
>
> And what about the IdEntry class?

The naming scheme doesn't hold up, but I'm pretty sure that's not what you mean?


> To me it would make more sense to
> customize the type of the .id value.

That sounds rather complex, like introducing a command pattern or something just
to support some debugging and testing.


[snippety]
>>>> This advantage of confidence in correctness can be realized even without
>>>> heavy reuse, because the encapsulation that's necessary for reuse, here
>>>> having the code in a class, also makes it possible with more centralized
>>>> testing.
>>> Was this sentence/paragraph produced by http://pdos.csail.mit.edu/scigen/
>>> ?
>> No. :-) But you're right that testing isn't that much of an issue for
>> that class. If that's what you meant.
>
> I read it twice but didn't understand it. You probably misplaced a word, but
> I can't figure out which one.

In general, if you encapsulate functionality in a class or function definition
or whatever, then you can move that code out to a module (or a package) and you
can then test the module and gain some confidence in its correctness.

In contrast, if you have nearly the same code duplicated in umpteen places,
doing just about the same but with local variations, then testing and especially
fixing it becomes more difficult and time consuming, and doesn't give you added
confidence about any new instances of that code pattern (with own variations).

But in this case the code to be duplicated is so small, just some glue for
calling a handler with an id, that it's difficult to get wrong. Even though
getting that wrong was exactly what this discussion thread started with. And so
the possible savings in the amount of work for testing and fixing is probably
(OK, weasel word) not that much of an issue in this case.


[snippety]
>>>
>>>>>> def __on_tk_command( self ):
>>>>>> if self.__specified_command != None:
>>>>>> self.__specified_command( self )
>>>>>> else:
>>>>>> self.on_clicked()
>> Uh, could you expand on how that's redundant and how to make it less so?
>
> How about
>
> class IdButton(tkinter.Button):
> def __init__(self, owner, id, command=None, **kwargs):
> tkinter.Button.__init__(
> self, owner, kwargs, command=self.on_clicked)
> self.id = id
> self.specified_command = command
>
> def on_clicked(self):
> if self.specified_command is not None:
> self.specified_command(self)

The only purpose I can see for on_clicked is that it can be overridden (that was
the purpose in my code too, a central customization point). But if anyone does
that then he or she now has to duplicate the original on_clicked() code, or else
ditch the per button customization via a supplied command handler function. I
feel that forced code duplication, forced redundancy, something you just have to
remember to add in the code, for the only purpose, is ungood.


Cheers,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 3, 2009, 5:29 PM

Post #21 of 35 (629 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Diez B. Roggisch:
> Alf P. Steinbach schrieb:
>> * Diez B. Roggisch:
>>>> Your comment about "computed" makes it more clear what that's all
>>>> about.
>>>> Also Bertrand Meyer (Eiffel language creator) had idea like that, he
>>>> called it "referential transparency". But I think when Python has this
>>>> nice property mechanism, why do people change direct data attributes
>>>> into
>>>> properties and not the other way around or not at all, I mean using
>>>> only
>>>> properties for logical
>>>> data attributes -- e.g. assuring correctness first via read-only
>>>> property?
>>>
>>> I fail to see where read-only-ness of an attribute is a priori more
>>> correct
>>> than having modifyable attributes.
>>
>> No, I didn't mean that it is more correct to have an attribute as
>> read-only. I meant that letting a logical data attribute start out as
>> a read only property can help to ensure correctness.
>
> Which is the same thing said with other words.

No, it's two different things.

Whether something is correct or not, it can help to ensure correctness.

For a different example of that, a formally incorrect debug thing can help to
ensure correctness.


>> 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.

Hence your conclusion is wrong. :-)


> - if you
> change semantics of something, code might break.

Yes, but that's totally out of the blue. If you, say, paint your nose bright
green, then people might stare at it. That has nothing to do do with anything
discussed here, and so anyone mentioning that as purportedly relevant to
anything discussed here, would implicitly be saying "I don't understand anything
abour it", and that's effectively what you're saying, sorry.

However, I do understand what got you confused.

Changing the internal representation of a class is not to change the class'
semantics. It belongs to the class only. Anyone availing himself or herself of
access to that internal representation is doing something that may or may not
work in the future and would ideally be doing it at own's risk, but as the
example above illustrated, they're most often doing it at *other*'s risk.

And so the issue is how to get them to not do it, even when they think that
nobody will check their code until next version of Lib XYZ comes in a year...

And that's where using properties from the start enters the picture, making it
less convenient for those tinkerers to use internal representation details.


> In Python, attributes
> are part of the public interface as long as you don't explicitly define
> them otherwise.

Not sure what that refers to.


> But preliminary assumptions about what could be in some yet unseen
> future is introducing more code with more chances of errors

No not really.


>, reducing
> the flexibility at the same time. I still fail to see where that's good.

Yes.

Consider the *nix convention for files, that they're just byte streams. They're
*restricted* to byte streams. That's darn inflexible, yes?

And totally ungood. :-) (Note: irony)


> Code for what you need code for. It works - in all languages, but
> especially in Python.

Whether that's good advice depends on what you're doing and in what kind of job
setting you're doing it. For many cases it is, in essence, a very selfish way.
It gets down to saving time *now* for increased future maintainance times for
others, which of course is the only rational choice /if/ one is sure to get away
with it. OK, I'm not antirely serious but it sounds like you're thinking in this
way, to some degree. But check out any debate on Python vs. Perl, in particular
about maintainability.


Cheers & hth.,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


steven at REMOVE

Nov 3, 2009, 9:35 PM

Post #22 of 35 (625 views)
Permalink
Re: Tkinter callback arguments [In reply to]

On Wed, 04 Nov 2009 02:29:21 +0100, Alf P. Steinbach wrote:

>>> 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


Given the semantics you specified, it is strictly irrelevant whether
R2.top is an attribute or a property. That's an implementation detail.

Now of course we're capable of imagining a rectangle class R3 where
R3.top is a property which has the side-effect of also changing R3.bottom
so as to avoid the resize. Great -- that's something you can't implement
(easily, if at all) with bare attributes. But that class is not R2, it
has different semantics to R2.

We're not opposed to properties where the functional requirements are
best suited by computed properties. But properties don't come for free,
and if you're going to implement functional behaviour *identical* to bare
attributes using properties, then what's the point?


>> - if you
>> change semantics of something, code might break.
>
> Yes, but that's totally out of the blue. If you, say, paint your nose
> bright green, then people might stare at it. That has nothing to do do
> with anything discussed here, and so anyone mentioning that as
> purportedly relevant to anything discussed here, would implicitly be
> saying "I don't understand anything abour it", and that's effectively
> what you're saying, sorry.

I'm afraid you have failed to understand Diez's point.

The hypothetical project using class R1 had a specified functional
behaviour: assigning to rectangle.top must move the rectangle, not resize
it. You have replaced it with a class that has different behaviour. Who
cares what the implementation is? It's the *change in behaviour* that
caused the breakage, regardless of whether R2.top is implemented as a
bare attribute or as a property.

In that regard, it is *no different* from changing R2.set_position() to
resize the rectangle.


> However, I do understand what got you confused.

I doubt that very much.


> Changing the internal representation of a class is not to change the
> class' semantics.

That's true, but that's not what you've done in your example. You've
clearly changes the class' semantics. You said so yourself:

"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."

Since in Python, non-underscore attributes are part of the public API,
the two classes have different semantics.


> It belongs to the class only. Anyone availing himself
> or herself of access to that internal representation is doing something
> that may or may not work in the future and would ideally be doing it at
> own's risk, but as the example above illustrated, they're most often
> doing it at *other*'s risk.

Irrelevant. In Python, attributes are frequently part of the class API.
If you have an attribute R1.top, then people will assign to it, and your
class should deal with it.

"Deal with it", by the way, may include saying "if you stuff something
crazy in the attribute, then you are responsible for breaking it". Python
classes tend to be written under the implicit promise/threat that if you
do something stupid, you're responsible for the breakage. That allows the
caller the responsibility to do something clever which you never thought
of without having to defeat your defensive code, but with great power
(duck-typing) comes great responsibility (don't set R1.top to None unless
you want to see some amusing exceptions).



> And so the issue is how to get them to not do it, even when they think
> that nobody will check their code until next version of Lib XYZ comes in
> a year...
>
> And that's where using properties from the start enters the picture,
> making it less convenient for those tinkerers to use internal
> representation details.

This is Python. Introspection is easy, and messing up your internals is
easy unless you write your class in C. Just because you hide something
behind a property doesn't mean we can't find it and do strange and
terrible things to it. We don't do it because when we do, it's our own
foot we're shooting.



>> In Python, attributes
>> are part of the public interface as long as you don't explicitly define
>> them otherwise.
>
> Not sure what that refers to.

Dear me. Here you are talking about "internals", and you don't see the
connection with the public interface?

Hint: if something is in the public interface, it isn't an internal
detail.



>> But preliminary assumptions about what could be in some yet unseen
>> future is introducing more code with more chances of errors
>
> No not really.

Of course it is. Properties are *code*. Every line of code can contain
bugs. Properties require testing. They don't fall from the sky and insert
themselves into your class, you have to write them, test them, debug
them, maintain them.



>>, reducing
>> the flexibility at the same time. I still fail to see where that's
>> good.
>
> Yes.
>
> Consider the *nix convention for files, that they're just byte streams.
> They're *restricted* to byte streams. That's darn inflexible, yes?

No. Anything can be represented by a byte stream with a known encoding,
provided you are willing to deal with errors.



--
Steven
--
http://mail.python.org/mailman/listinfo/python-list


alfps at start

Nov 3, 2009, 10:15 PM

Post #23 of 35 (627 views)
Permalink
Re: Tkinter callback arguments [In reply to]

* Steven D'Aprano:
> On Wed, 04 Nov 2009 02:29:21 +0100, Alf P. Steinbach wrote:
>
>>>> 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.


> Given the semantics you specified

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.


> it is strictly irrelevant whether
> R2.top is an attribute or a property. That's an implementation detail.

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.


Cheers, & hth.,

- Alf
--
http://mail.python.org/mailman/listinfo/python-list


gagsl-py2 at yahoo

Nov 3, 2009, 11:37 PM

Post #24 of 35 (622 views)
Permalink
Re: Tkinter callback arguments [In reply to]

En Wed, 04 Nov 2009 03:15:14 -0300, Alf P. Steinbach <alfps [at] start>
escribió:
> * Steven D'Aprano:
>> On Wed, 04 Nov 2009 02:29:21 +0100, Alf P. Steinbach wrote:
>>
>>>>> 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.

>> Given the semantics you specified
>
> 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.

>> it is strictly irrelevant whether R2.top is an attribute or a property.
>> That's an implementation detail.
>
> 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.

--
Gabriel Genellina

--
http://mail.python.org/mailman/listinfo/python-list


__peter__ at web

Nov 3, 2009, 11:47 PM

Post #25 of 35 (628 views)
Permalink
Re: Tkinter callback arguments [In reply to]

Alf P. Steinbach wrote:

> * Peter Otten:
>> * Alf P. Steinbach wrote:
>>> * Peter Otten:
>>>> Every time someone has to read the code he will read, hesitate, read
>>>> again, and then hopefully come to the conclusion that the code does
>>>> nothing, consider not using it, or if it is not tied into a larger
>>>> project removing it.
>>> I don't understand what you mean.
>>
>> Writing code is not fire and forget. It has to be debugged, tested,
>> maintained, and will be read quite a few times in the process. Therefore
>> it is important that you make it easy to read and understand.
>
> 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)).

>>>> Example: Why do you introduce button.id_string() instead of
>>>> str(button.id)?
>>> Because the string representation of an id then /can/ be customized
>>> independently of the id. For example, id's might be integers but for
>>> string representation you might want symbolic action names (e.g., you
>>> might have two or more buttons with same title but different actions, so
>>> that title would be ungood to identify button). And for another example,
>>> when debugging or testing you might want the string represention of an
>>> id to provide more information about the button and/or its context, and
>>> then id_string provides a single
>>> central customization point -- provided it's used, of course. <g>
>>
>> And what about the IdEntry class?
>
> 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

--
http://mail.python.org/mailman/listinfo/python-list

First page Previous page 1 2 Next page Last page  View All Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.