I don't feel authoritative on the correctness/appropriateness of the
implementation, but I do agree completely that behavior b, or what you
have in the 3.0 version, is vastly preferable.
Hi,
this posting - concerning the new turtle module - goes to the
Python-Dev and Python-3000 lists and to a couple of 'power users' of
turtle graphics, hoping to recieve feedback from the developer's
point of view as well as from the user's point of view.
Currently the implementations of the turtle.Screen class for Python
2.6 and Python 3.0 differ by a 'tiny' detail with an important
difference in behaviour. So clearly this has to be resolved before
the final release.(The origin of this difference is, that when I
ported turtle.py to Python 3.0 I discovered (and 'fixed') what I now
consider to be a bug in the 2.6 version.) I'd like to ask you kindly
for your advice to achieve an optimal solution.
The posting consists of three parts:
1. Exposition of design goals
2. Problem with the implementation 3. How to solve it?
Preliminary remark: I've had some discussions on this topic before
but I still do not see a clear solution. Moreover I'm well aware of
the fact that using the Singleton pattern is controversial. So ...
1. Exposition of design goals
... why use the Singleton design pattern? The turtle module contains
a TurtleScreen class, which implements methods to control the drawing
area the turtle is (turtles are) drawing on. It's constructor needs a
Tkinter Canvas as argument. In order to avoid the need for users to
tinker around with Tkinter stuff there is the Screen(TurtleScreen)
class, designed to be used by beginners(students, kids,...),
particularly in interactive sessions.
A (THE (!)) Screen object is essentially a window containing a
scrolled canvas, the TurtleScreen. So it's a ressource which should
exist only once. It can be constructed in several ways:
- implicitely by calling an arbitrary function derived from a
Turtle-method, such as forward(100) or by constructing a Turtle such
as bob = Turtle()
- implicitely by calling an arbitrary function derived from a Screen
method, such as bgcolor("red")
- explicitely by calling it's constructor such as s = Screen()
Anyway this construction should only happen if a Screen object
doesn't exist yet.
Now for the pending question: What should happen, when s = Screen()
is called explicitely and there exists already 'the' Screen object.
(i) Clearly s should get a reference to the existing Screen object,
but ...
(ii) (a)... should s be reinitialized (this is the case now in Python
2.6), or
(b)... should s be left untouched (this is the case now in Python
3.0)
I, for my part, prefer the latter solution (b). Example: a student,
having (interactively) produced some design using some turtle t =
Turtle() decides spontaneously to change backgroundcolor. s =
Screen(); s.bgcolor("pink") should do this for her - instead of
deleting her design and moreover her turtle. To reinitialize the
screen she still can use s.clear().
Of course, there are workarounds to achieve the same effect also with
solution (a), for instance by assigning s = Screen() *before* drawing
anything or by assigning s = t.getscreen(). But imho (which derives
itself from my experience as a teacher) solution (b) supports better
the oop-view as well as experimenting spontaneously in interactive
sessions.
2. Problem with the implementation
The task is to derive a Singleton class from a Nonsingleton class
(Screen from TurtleScreen). The current implementations of the Screen
'Singleton' both use the Borg idiom. Just for *explaining* the
difference between the two versions of class Screen here concisely,
I'll use a 'standard' Singleton pattern (roughly equivalent to the
Borg idiom):
class Spam(object):
def __init__(self, s):
self.s = s
class SingleSpam(Spam):
_inst = None
def __new__(cls, *args, **kwargs): if cls !=
type(cls._inst):
cls._inst = Spam.__new__(cls, *args, **kwargs)
return cls._inst
def __init__(self, s):
if vars(self): return ###### should this be here???
Spam.__init__(self, s)
Shortly, this means that SingleSpam.__init__() acts like an empty
method whenever a (the!) SingleSpam object already exists. 3.0
version of Screen acts like this. By contrast 2.6 version of Screen
acts as if the butlast line were not there and thus reinitializes the
Screen object.
3. How to solve it?
Main question: which *behaviour* of the Screen class should be
preferred. If 3.0, is it feasible and correct not to call the
constructor of the parent class if the object already exists?
Additional question: Do you consider the Borg idiom a good solution
for this task or should the standard singleton pattern as shown above
be preferred. Or would you suggest a solution/an approach different
from both?
Thanks for your patience, and - in advance - for your assistance
Regard,
Gregor