singleton ... again

A

Asaf Las

playing a bit with subject.

pros and cons of this approach? did i create bicycle again? :)

class myclass(object):
class_instance = None

def __new__(cls, *args, **kwargs):
if myclass.class_instance == None:
return object.__new__(cls)
return myclass.class_instance

def __init__(self, some):
if self.__class__.class_instance == None: # init blocker
self.__class__.class_instance = self
self.member = some

def __del__(self):
self.__class__.class_instance = None

one_class = myclass(1)
print(id(one_class), one_class.member )

two_class = myclass(2)
print(id(two_class), two_class.member)
 
A

Asaf Las

there is error should assign weakref to class static member otherwise __del__
will never be called.
 
D

Dave Angel

Asaf Las said:
playing a bit with subject.

pros and cons of this approach? did i create bicycle again? :)

class myclass(object):
class_instance = None

def __new__(cls, *args, **kwargs):
if myclass.class_instance == None:
return object.__new__(cls)
return myclass.class_instance

def __init__(self, some):
if self.__class__.class_instance == None: # init blocker
self.__class__.class_instance = self
self.member = some

def __del__(self):
self.__class__.class_instance = None

one_class = myclass(1)
print(id(one_class), one_class.member )

two_class = myclass(2)
print(id(two_class), two_class.member)

Perhaps if you would state your actual goal, we could judge
whether this code is an effective way to accomplish
it.
 
R

Roy Smith

Dave Angel said:
Perhaps if you would state your actual goal, we could judge
whether this code is an effective way to accomplish
it.

It looks to me like he's trying to implement a classic Gang of Four
singleton pattern.
 
G

Gregory Ewing

Roy said:
It looks to me like he's trying to implement a classic Gang of Four
singleton pattern.

Which I've never really seen the point of in Python,
or any other language for that matter. Just create
one instance of the class during initialisation,
put it in a global somewhere, and use it thereafter.

If you really want to make sure nobody creates
another instance by accident, delete the class
out of the namespace after instantiating it.
 
R

Roy Smith

Ben Finney said:
Make that “somewhere†a module namespace, and you effectively have a
Singleton for all practical purposes. So yes, I see the point of it; but
we already have it built in :)

This is one of the big problems with the Gang of Four book (and most of
the pattern literature). They present these patterns as universal to
all OOPL's, when in reality, so much of them is "Things I need to do to
appease the C++ compiler".
 
A

Asaf Las

Perhaps if you would state your actual goal, we could judge
whether this code is an effective way to accomplish
it.
DaveA

Thanks!

There is no specific goal, i am in process of building pattern knowledge
in python by doing some examples.
 
A

Asaf Las

There is another one.
Once object passes through singletonizator
there wont be any other object than first one.

Then object constructor can freely be used in every place
of code.
Curious if there could be any impact and applicability
of this to builtin types.

p.s. learned today that object __init__ member function is bound
to its class :)

class singletonizator(object):
def __new__(cls, *args, **kwargs):

def newnew(cls, *args, **kwargs):
print("in new new", cls)
return cls.__dict__['hidden_object']

def newinit(self, *args, **kwargv):
print("in new init", self)
pass

if not 'hidden_object' in args[0].__class__.__dict__:
setattr(args[0].__class__, 'hidden_object', args[0])
args[0].__class__.__new__ = newnew
args[0].__class__.__init__ = newinit
return args[0]

class SomeClass:
def __init__(self, num):
print("in original init", self)
self.mynum = num

first_object = singletonizator(SomeClass(1))
print(first_object, first_object.mynum)

second_object = singletonizator(SomeClass(2))
print(second_object, second_object.mynum)

third_one = SomeClass(3)
print(third_one, second_object.mynum)

exit()


in original init <__main__.SomeClass object at 0x0000000002F338D0>
<__main__.SomeClass object at 0x0000000002F338D0> 1
in new new <class '__main__.SomeClass'>
in new init <__main__.SomeClass object at 0x0000000002F338D0>
<__main__.SomeClass object at 0x0000000002F338D0> 1
in new new <class '__main__.SomeClass'>
in new init <__main__.SomeClass object at 0x0000000002F338D0>
<__main__.SomeClass object at 0x0000000002F338D0> 1
 
M

Mark Lawrence

Thanks!

There is no specific goal, i am in process of building pattern knowledge
in python by doing some examples.

For more data on python patterns search for
python+patterns+Alex+Martelli. He's forgotten more on the subject than
many people on this list will ever know :)
 
N

Ned Batchelder

Thanks!

There is no specific goal, i am in process of building pattern knowledge
in python by doing some examples.

Not all patterns are useful. Just because it's been enshrined in the
GoF patterns book doesn't mean that it's good for Python.

I don't understand why you would like a class to pretend to make new
instances, but actually lie and return the same instance over and over.
It makes them impossible to test: your unit tests all act on the same
object, there's no way to start over with a fresh object.

If you only want one object, create just one, and use it everywhere.
 
G

Gregory Ewing

Asaf said:
There is another one.
Once object passes through singletonizator
there wont be any other object than first one.

Then object constructor can freely be used in every place
of code.

You're still making things far more complicated
than they need to be.

*Why* do you want to be able to use the object
constructor, instead of just using the prebuilt
instance?

If you want to hide the distinction between using
call syntax and just accessing a global, then
export a function that returns the global instance.

That function can even lazily create the instance
the first time it's called. That's a pattern that
*is* useful, and I've often used in Python and
other languages.

E.g.

_the_whatsit = None

def get_whatsit():
if _the_whatsit is None:
_the_whatsit = Whatsit()
return _the_whatsit
 
M

Michael Torrie

playing a bit with subject.

pros and cons of this approach? did i create bicycle again? :)

I always thought sticking an object in a module is the simplest form of
singleton.
 
A

Asaf Las

For more data on python patterns search for
python+patterns+Alex+Martelli. He's forgotten more on the subject than
many people on this list will ever know :)

My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

Oh, thanks, good information.
 
A

Asaf Las

Not all patterns are useful. Just because it's been enshrined in the
GoF patterns book doesn't mean that it's good for Python.

Yes, i understand up to some extend usefulness of patterns.
i did not read the GoF book. yet.
I don't understand why you would like a class to pretend to make new
instances, but actually lie and return the same instance over and over.
It makes them impossible to test: your unit tests all act on the same
object, there's no way to start over with a fresh object.

If you only want one object, create just one, and use it everywhere.

Ned Batchelder, http://nedbatchelder.com

Actually it is not about singleton. Let say if i would like to make set
of resources with controllable quantity and not for single class but
for let say 10 or 20 classes , so i could read config file at time of program
start and create them accordingly and only when needed.
having unified attribute names within resource classes allows to do more
more from one place, let say leaving resource recovery to background thread
via proxy methods for failed resources, or scanning of objects in resource
for timeouts or ticking clocks on them for delayed response.

if there is no unified template - then for every particular class i have to
put a list within module and count on number of objects created and then supervision and other things have to be handled separately. Though i do not
defend current approach - it is a bit hack. same can be done via inheritance
from base classes or with a bit more typing via static methods.

Asaf
 
A

Asaf Las

If you want to hide the distinction between using
call syntax and just accessing a global, then
export a function that returns the global instance.

That function can even lazily create the instance
the first time it's called. That's a pattern that
*is* useful, and I've often used in Python and
other languages.
E.g.
_the_whatsit = None
def get_whatsit():
if _the_whatsit is None:
_the_whatsit = Whatsit()
return _the_whatsit
Greg

Gregory Ewing and Michael Torrie, yes you are both right, that is how things
are done in standard Python library. But i am not restricting myself to that.

Thanks

/Asaf
 
R

Roy Smith

Asaf Las said:
Thanks!

There is no specific goal, i am in process of building pattern knowledge
in python by doing some examples.

That is a worthy goal. Patterns are interesting, and sometimes useful.
Sometimes they're useful just as a vocabulary to help you think and talk
about program structure.

Just be aware that, like so many good things, a whole religion has grown
up around them. Understanding the concept without getting sucked into
the religion is a good goal.
 
S

Steven D'Aprano

Which I've never really seen the point of in Python, or any other
language for that matter. Just create one instance of the class during
initialisation, put it in a global somewhere, and use it thereafter.

If you really want to make sure nobody creates another instance by
accident, delete the class out of the namespace after instantiating it.

That does not work. It is trivial to get the type from an instance:


py> class Singleton:
.... pass
....
py> S = Singleton()
py> del Singleton
py> T = type(S)()
py> S
<__main__.Singleton object at 0xb71de9ec>
py> T
<__main__.Singleton object at 0xb71dea2c>




This is not aimed at the original poster, just a general observation. The
Singleton design pattern is overused because it is probably the only
design pattern that most programmers really understand.
 
S

Steven D'Aprano

Steven D'Aprano said:
If you really want to make sure nobody creates another instance by
accident, delete the class out of the namespace after instantiating
it.

That does not work. It is trivial to get the type from an instance [by
calling ‘type(foo)’].

Right, but surely you don't think people would do that “by accidentâ€,
which is what Gregory was addressing.

Of course it can happen by accident. It's happened to me, where I've
accidentally called NoneType() (which raises, rather than returning a new
instance).

The way it happened is I had a bunch of numeric values, all of the same
type, and wanted to test that summing them with a custom sum function
would give the same result whether I provided a start parameter or not:

for data in list_of_datas:
T = type(data[0])
zero = T()
assert sum(data) == sum(data, zero)


only somehow one of the data sets ends up containing None due to another
bug. Now in *this* case, the error was obvious: NoneType() raises an
exception. If the type happened to be bool(), I would have been okay too,
because bool() returns the appropriate singleton True instance.

Because I was testing a function with no side-effects, it wouldn't have
mattered even if I had accidentally created a extra instance of something
which nominally ought to have been a singleton. But if I were testing a
function with side-effects, say one which modifies the internal state of
the singleton, then I could have been in all sorts of strife.

If you're going to have a singleton, you ought to do one of two things:

* calling the constructor returns the same singleton each time; or

* calling the constructor (apart from the very first time) raises an
exception.


I prefer the first case.
 
C

Chris Angelico

Of course it can happen by accident. It's happened to me, where I've
accidentally called NoneType() (which raises, rather than returning a new
instance).

It does in 2.7, yes, but not in 3.4:
True

Definitely prefer returning the singleton to raising.

ChrisA
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,047
Members
48,769
Latest member
Clifft

Latest Threads

Top