[Python-3000] turtle.Screen- how to implement best a Singleton
Gregor Lingl
gregor.lingl at aon.at
Mon Aug 18 14:14:33 CEST 2008
Thanks for the feedback,
Gregor
Vern Ceder schrieb:
> Gregor,
>
> 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.
>
> Cheers,
> Vern
>
> Gregor Lingl wrote:
>> 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
>>
>>
>>
>>
>
More information about the Python-3000
mailing list