Why does passing tuple as arg WITHOUT scattering work?

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Tue Oct 20 20:00:02 EDT 2009


En Tue, 20 Oct 2009 18:42:07 -0300, Alf P. Steinbach <alfps at start.no>  
escribió:

> I'm just learning Python from scratch, on my own. Apologies if this  
> question is too newbie... Or perhaps answered in some FAQ (where?).

Welcome! I hope you'll enjoy the language. And no, it's not a trivial  
question.

> import Tkinter
> canvas = Tkinter.Canvas( window, bg = "white" )
> bbox = 2, 2, 347, 197
> canvas.create_oval( bbox, fill = "PeachPuff" )
> [...]

> It worked nicely, and I thought this code was fairly perfect until I  
> started studying the language reference.
>
> It seems that formally correct code should apply the scatter operator to  
> the tuple, like this:
>
> canvas.create_oval( *bbox, fill = "PeachPuff" )
>
> And this /also/ works nicely!
>
> I think it's this latter that is correct, and that the former just  
> worked by accident, due to e.g. the way that some C function parses  
> arguments or such?
> But I'm unable to figure it out, so, what's correct (both? one?), and  
> assuming it's the latter that's correct, would the first version still  
> work in practice regardless of Python / Tkinter implementation?

You can look for yourself, the high-level functions in Tkinter are written  
in Python (there is a compiled C module too, _tkinter). Look into  
Lib\lib-tk\Tkinter.py, Canvas.create_oval.

Warning: Tkinter is a very old library, and its code is not  "pythonic"  
enough by today's standards. In particular, Tkinter was originally written  
_before_ the *args, **kw syntax was available. Several functions took a  
_tuple_ of parameters and an explicit _dictionary_ for optional  
parameters; support for variable number of arguments was added later.
The code is written in such a way to collect all positional arguments into  
a tuple (flattening any inner list or tuple); if the last item in that  
tuple is a dictionary, it is removed and used as the base options. Those  
options are combined with an argument named "cnf" (which must be a  
dictionary) and finally combined with any other named argument. That is,  
it was (and still is) possible to write:

bbox = 2, 2, 347, 197
canvas.create_oval([bbox], {"fill" : "PeachPuff"})

instead of:

canvas.create_oval(bbox, fill="PeachPuff")

or even:

canvas.create_oval(2, 2, 347, 197, fill="PeachPuff")

In the end, the Tcl statement actually executed is like this:

.canvasname create oval 2 2 347 197 -fill PeachPuff

so it doesn't really matter how those parameters are passed.

> But I'm unable to figure it out, so, what's correct (both? one?), and  
> assuming it's the latter that's correct, would the first version still  
> work in practice regardless of Python / Tkinter implementation?

I'd use the "modern" interface, that is, keyword arguments (instead of an  
explicit dictionary). Although the documentation warns against the "old"  
way, the fact is that Tkinter has changed very little in years, and the  
cnf parameter is still there in version 3.1

-- 
Gabriel Genellina




More information about the Python-list mailing list