I've just noticed that the Singleton design pattern Wikipedia page (http://en.wikipedia.org/wiki/Singleton_pattern) was changed on the 29th of January to include an example of Python code for an inheritable singleton:
http://en.wikipedia.org/w/index.php?title=Singleton_pattern&diff=104294450&oldid=104070484 Edward On Thu, 2007-03-22 at 11:39 +0000, Chris MacRaild wrote: > On Thu, 2007-03-22 at 15:09 +1100, Edward d'Auvergne wrote: > > As far as I'm concerned there is absolutely nothing stopping me in > > Python from creating a base class with singleton properties and then > > subclassing this to create independent singletons that I can use for > > different purposes. An example of a singleton base class and > > inheritance could be as follows. Say I create a base class > > SingletonQueue that has advanced queuing properties (say to be thread > > safe) together with the properties of being a singleton. Then I > > create ResultsQueue(SingletonQueue) to queue model-free optimisation > > results coming in from remote machines on a grid (there is only one > > instance of this queue in the program). I also create > > OptimisationQueue(SingletonQueue) which is a queue for each > > optimisation to be sent out to a grid computer (again there is only > > one instance of this queue in the program). These two queues benefit > > from being thread safe. Now, what exactly is stopping me from doing > > this? And what is stopping me from using SingletonQueue as a third > > singleton object for a completely unrelated purpose? What if > > SingletonQueue was actually named ThreadQueue and was used as a queue > > of threads awaiting execution? I could use all these three queues, > > they would be singletons, and their namespaces will never clash! > > Python has never claimed to be an arbiter of logic, or even of good > programming practise - just because Python allows you to do it, it > doesn't mean it makes sense, or that it is a good idea. No-one is > suggesting there is any impediment to what you describe, except for the > fact that SingletonQueue is no longer a singleton, because both the > single instance of ResultsQueue and the single instance of > OptimisationQueue are also instances of SingletonQueue. You have two > instances of the same class, therfore the class is not a singleton. > > Here is how to impliment exactly what you describe, without breaking the > singleton design pattern: > > >>> class AbstractQueue: > ... # NOTE: this is NOT a singleton! > ... # define a general queue here > >>> class ResultsQueue(AbstractQueue): > ... # modify the default queue for results > >>> class OptimisationQueue(AbstractQueue): > ... # modify the default queue for oplimisations > >>> ResultsQueue = ResultsQueue() > >>> OptimisationQueue = OptimisationQueue() > > We have exactly one instance of ResultsQueue and OptimisationQueue, so > both are singletons, as per the design. AbstractQueue never claimed to > be a singleton, because it isn't - ResultsQueue and OptimisationQueue > are both instances of AbstractQueue. > > > > > For discussions about inheritance of singletons, see the Python > > cookbook (http://aspn.activestate.com/ASPN/Cookbook/Python). Examples > > include: > > > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187 (see > > the comments section). > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 (see the > > comment with the title 'Singletons using new-style classes') > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/113657 (this > > singleton 'behaves well with inheritance') > > Sure, but there are plenty of contradictory statements here too, eg.: > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 > (inheriting singleton vs inheriting borg): > "What happens in a large system when two separate subsystems both > inherit from (extend) a singleton-class? It's anything but clear to me > -- error at runtime, at compiletime, at linktime (none such in Python, > let's say at import-time), or what behavior...?" > > http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/465850: > "One problem introduced here is that inheritance is broken, but that is > more of a problem of the Singleton pattern than of this recipe." > > > The moral: you can find someone on a public message board to support > almost any opinion. > > > > > > > As for instances of base classes, towards the bottom of the Wikipedia > > page http://en.wikipedia.org/wiki/Inheritance_(computer_science) there > > is the text: > > > > "In most quarters, class inheritance for the sole purpose of code > > re-use has fallen out of favor. The primary concern is that > > implementation inheritance does not provide any assurance of > > polymorphic substitutability—an instance of the re-using class cannot > > necessarily be substituted for an instance of the inherited class. An > > alternative technique, delegation, requires more programming effort > > but avoids the substitutability issue." > > > > According to this statement 'an instance of the re-using class' is > > different to the 'instance of the inherited class'. The rest of this > > text is opinion. > > Well, at least you are honest about quoting selectively. Infact > polymorphism can be rather a headache in many languages, but in this > respect Python is much beter than most. Of course 'an instance of the > re-using class' is different to the 'instance of the inherited class', > but the instance of the re-using class is also an instance of the > inherited class. ie. there are two classes, two objects, and three > instance relationships linking the classes with the objects: the one > object is just an instance of the base class, while the other object is > an instance of both the base class and the sub-class. > > > Now according to > > http://en.wikipedia.org/wiki/Instantiation_(computer_science): > > > > "Instantiation is the process of creating a specific object which is a > > member or instance of a class." > > > > Hence the instance is a specific object. As the specific object lies > > at a specific point in memory space, then if two variables point to > > the same instance then the Python the 'id()' function will return the > > same number. According to that function's docstring: > > One subtle point that might help here - 'instance' refers first to a > relationship, it is only a conventional shorthand that allows us to say > 'the instance is an object'. Instance is a non-exclusive relationship > between two objects, so there can be many instance relationships between > only a few objects. This can lead to confusion if we take too litteraly > the 'instance is an object' type shorthand and try to generate a > one-to-one correspondence between instancehood and object. > > > > > Help on built-in function id in module __builtin__: > > > > id(...) > > id(object) -> integer > > > > Return the identity of an object. This is guaranteed to be unique among > > simultaneously existing objects. (Hint: it's the object's memory > > address.) > > > > To demonstrate this, try importing the 'singleton_inheritance' module > > attached to my message at > > https://mail.gna.org/public/relax-devel/2007-03/msg00077.html (the > > text at the very bottom) and running the id() functions on the two > > singletons: > > > > relax> import singleton_inheritance > > > > Singleton is NewSingleton: False > > Contents of Singleton: ['__doc__', '__init__', '__module__', 'a', > > 'base_fn', 'x'] > > Contents of NewSingleton: ['__doc__', '__init__', '__module__', 'a', > > 'base_fn', 'new_fn', 'x', 'y'] > > Singleton.base_fn is NewSingleton.base_fn: False > > > > Singleton.a: 1 > > NewSingleton.a: -1 > > Singleton.x: 2 > > NewSingleton.x: 3 > > > > Singleton.base_fn(): > > Hello > > NewSingleton.base_fn(): > > Hello > > NewSingleton.new_fn(): > > Bye > > relax> id(singleton_inheritance.Singleton) > > 1080385452 > > relax> id(singleton_inheritance.NewSingleton) > > 1083092716 > > > > These are two different memory addresses. Hence these are two > > different objects. They are also 'simultaneously existing objects'. > > As an instance is a specific object, and here with have two specific > > objects, we have two instances. QID! > > QID what? You have convinsingly demonstrated that two different objects > are indeed two different objects. This has no bearing on whether they > share instance relationships with the base class. Indeed the fact that > the are two different objects is exactly why they breach the singleton > design of the base class. > > > Chris > > > > > > Bye, > > > > Edward > > > > > > On 3/22/07, Chris MacRaild <[EMAIL PROTECTED]> wrote: > > > On Sat, 2007-03-17 at 12:27 +1100, Edward d'Auvergne wrote: > > > > The attached file is a Python module, try importing it and then > > > > playing with its contents. The module contains two singletons - > > > > 'Singleton' and 'NewSingleton'. Both are instantiated in the same > > > > manner as new relax data storage object (implementation B which we > > > > voted for), the class name being masked by the instance reference. > > > > NewSingleton is derived from the Singleton base class demonstrating > > > > inheritance. QID! > > > > > > > > These singletons are two completely different objects (in different > > > > memory space) which can be used for completely different tasks and can > > > > be used by completely different parts of the program all while being > > > > true singletons - only one instance of each will ever exist in the > > > > program. If you cannot see this, I challenge you to write a counter > > > > example module demonstrating that what this extremely basic module is > > > > doing cannot be done. > > > > > > What this module is doing can be done (of course), but it breaks the > > > Singleton design because: > > > > > > >>> isinstance(NewSingleton, Singleton.__class__) > > > True > > > > > > Contrary to your previous assertions, isinstance is aptly named, and > > > correctly identifies the inheritance relationship between these two > > > objects. In other words, because NewSingleton inherits from > > > Singleton.__class__ (ie. the class, not the instance of the same name), > > > NewSingleton is an instance of Singleton.__class__ > > > > > > This is fundamental to the nature of inheritance, and is the basis of > > > our dissagreements. Again, the classic inheritance metaphor: class Apple > > > is a subclass of the class Fruit, and GrannySmith is a subclass of the > > > Apple. Your argument that an object cannot be an instance of more than > > > one class flies in the face of reason - quite clearly, any object which > > > is an instance of the class GrannySmith, is also an instance of Apple > > > and of Fruit. This is essential to the nature of sub-classing, in both > > > common logic and in OO programing. > > > > > > Perhaps it is helpful to consider the distinction between Inheritance > > > and Delegation. Both achieve similar things in terms of code reuse and > > > behavioural modification, but they do so in quite different ways, and > > > have important functional differences. Given some base class with lots > > > of methods that I want to access, while making a few changes: > > > > > > >>> class Base: > > > ... def methodA(self): > > > ... print "A" > > > ... def methodB(self): > > > ... print "B" > > > ... # lots more methods... > > > > > > I could inherit from Base, and change the functionality: > > > > > > >>> class Inherited(Base): > > > ... def methodA(self): > > > ... print "a\n" > > > > > > Or I could delegate to Base those methods that I don't redefine: > > > > > > >>> class Delegated: > > > ... def methodA(self): > > > ... print "a\n" > > > ... def __getattr__(self, attr): > > > ... # If attribute lookup fails, delegate to Base > > > ... return getattr(Base(), attr) > > > > > > Instances of the two classes, Inherited and Delegated, are functionally > > > very similar: they have all of the same methods, most of which are > > > identical to those of Base. There is one important difference: > > > > > > >>> isinstance(Inherited, Base) > > > True > > > >>> isinstance(Delegated, Base) > > > False > > > > > > A great example of inheritance in the sense I am describing comes from > > > the Python exceptions system. All python exceptions are an instance of > > > the base class Exception, and from there ther exists a hierachy of > > > exceptions: ArithmeticError is a subclass of Exception, and in turn is a > > > base class for all of the standard maths errors (OverflowError, > > > ZeroDivisionError, etc); likewise LookupError derives from Exception, > > > and is base class for KeyError and IndexError. This hierachy is very > > > powerful, because it allows us to handle different types of error in > > > different ways: > > > > > > >>> try: > > > ... errorProneFunction(args) > > > ... except LookupError: > > > ... dealWithLookupError(args) > > > ... except ArithmeticError: > > > ... dealWithArithmeticError(args) > > > ... except: > > > ... # All other errors > > > ... dealWithOtherError(args) > > > > > > Suppose there is a case that I want to catch as an exception, that is > > > maths-related. Although it is not one of the standard maths errors, I > > > want to handle it in the same way (with the function > > > dealWithArithmeticError() ). I simply need to subclass from > > > ArithmeticError: > > > > > > >>> class MyMathsError(ArithmeticError): > > > ... pass > > > > > > This works because an exception which is an instance of MyMathsError is > > > also an instance of ArithmeticError, so the statement except > > > ArithmeticError will catch MyMathsError, as well as OverflowError, > > > ZeroDivisionError and the rest. Importantly, no amount of delegation > > > will make this work: > > > > > > >>> class AnotherMathsError: > > > ... def __getattr__(self, attr): > > > ... # If attribute lookup fails, delegate to Base > > > ... return getattr(ArithmeticError(), attr) > > > > > > AnotherMathsError is not caught by except ArithmeticError, because it > > > lacks the requisite inheritance relationship - it is not an instance of > > > ArithmeticError. > > > > > > So, to restate what I think is the orthodox OO understanding of > > > inheritance: any object which is an instance of a sub-class S is also an > > > instance of all of the classes which are base-classes of S. This is > > > stated somewhat obtusely at http://en.wikipedia.org/wiki/Inheritance_% > > > 28computer_science%29 in the second paragraph: > > > > > > "Inheritance is also sometimes called generalization, because the is-a > > > relationships represent a hierarchy between classes of objects. For > > > instance, a "fruit" is a generalization of "apple", "orange", "mango" > > > and many others. One can consider fruit to be an abstraction of apple, > > > orange, etc. Conversely, since apples are fruit (i.e. an apple is-a > > > fruit), apples may naturally inherit all the properties common to all > > > fruit, such as being a fleshy container for the seed of a plant." > > > > > > and (similarly obscurely) in almost all basic descriptions of Object > > > Orientated coding. This is critically important, because it allows > > > client code to use instances of the sub-class as if they were instances > > > of the base-class, without knowing anything about the properties (or > > > even the existance) of the sub-class. > > > > > > Chris > > > > > > > > > > > > > > > > > > _______________________________________________ relax (http://nmr-relax.com) This is the relax-devel mailing list [email protected] To unsubscribe from this list, get a password reminder, or change your subscription options, visit the list information page at https://mail.gna.org/listinfo/relax-devel

