Singleton?

James T. Dennis jadestar at idiom.com
Sun Jan 27 17:03:02 EST 2002


Jason Orendorff <jason at jorendorff.com> wrote:

> James T. Dennis writes:
>>  Would this be considered to be a valid implementation of 
>>  the GoF "singleton" pattern?

>> [...]

>>  My test suite passes, of course.  But I'm not sure if this
>>  would count as a valid "singleton" though it does seem to 
>>  exhibit the desire behavior.  It this "cheating?"  What are
>>  the consequences of this approach?

> (grin) Cheating??  Your approach is about as good as any.

> There are many approaches.  My favorite, when it's feasible, is:

>   class _X:
>       """ NOTE: Do not instantiate this class!  Use x instead. """
>       pass

>   x = _X()  # singleton instance

 This is similar to an option I considered:

     class _X:
	"""Singleton Shadow Class: Don't Instantiate Directly"""
	def __init__(s):
		s.instantiatedflag=s
	...

     class X:
	"""Instantiate me so I can call on my shadow"""

	# ???

 ... on the idea that X is sort of a proxy to the real (shadow)
 class _X.  The proxy would enforce the singleton nature of the 
 _X (or I could raise some sort SingletonInstantiation exception).

 I understand that the main detrimental consequence of my approach 
 is that my "class" can't be subclassed.  My main goal was to 
 allow multiple attempts at instantiation to occur without error
 while still guaranteeing a singleton.  What I'd like to do is have
 some sort of __instantiate__() member that would allow a class to
 return a custom object reference.  

 I can see the problem:  __init__(self, ...) needs a "self" which 
 is why it can't return a value.  If we had  an __instantiate__()
 (which could NOT have a "self" argument, or any other since those are
 appended to the self argument that's passed to __init__() then 
 we could have it return an object reference (singleton or from a
 pool) or raise and exception.

 Would that make for a reasonable PEP?  Foo.__instantiate__() is 
 called by:  a=Foo() and it can return an object reference or 
 raise an exception.  So the sequence (internally) would go 
 something like:

	parser/engine sees:  a=Foo()
	it finds the class Foo
	if Foo.__instantiate__ exists:
		call it
		# must return an object reference 
	else:
		instantiate a generic object
	# either way we get "self"
	if Foo.__init__ exists:
		call it with "self" and any args, kwargs, etc
	return self  (binding/assigning it to a

 As I say, this would make singletons trivially easy, we'd just
 have an _instantiated member

 class Foo:
	_instantiated=None
	def __instantiate():
		if _instantiated:
			return _instantiated
		else:
			Foo._instantiated=Object() ## Generic obj

	## ...

 ... but it would also allow us to have object pools (so we could
 easily have some large number of objects which are used, thrown
 into the "free" pool and then available for re-use).  I surprised
 that the GoF didn't have an "Pool" pattern for just this sort of
 us; on the notion that instantiating new objects can be expensive
 and lead to memory fragmentation (possibly causing excessive GC)
 while re-using previously instantiated objects might be considerably
 less expensive.

 I'm not sure what other uses it might have.

 Should I submit that as a PEP?  (I don't know anything about the
 PEP marshalling process, though I seem PEPs or proto-PEPs shot down
 in flames on this newsgroup on a regular basis).




More information about the Python-list mailing list