SIngleton from __defaults__

A

Asaf Las

Hi

Inspired by "Modifying the default argument of function"
https://groups.google.com/forum/#!topic/comp.lang.python/1xtFE6uScaI

is it possible to create singleton using construct below :

def singleton_provider(x = [None]):
if singleton_provider.__defaults__[0][0] == None:
singleton_provider.__defaults__[0][0] = SomeClass()
return singleton_provider.__defaults__[0][0]

and question - how to make it work in multithreaded app
when multiple threads are racing to create it first?

Thanks

Asaf
 
C

Chris Angelico

is it possible to create singleton using construct below :

def singleton_provider(x = [None]):
if singleton_provider.__defaults__[0][0] == None:
singleton_provider.__defaults__[0][0] = SomeClass()
return singleton_provider.__defaults__[0][0]

Why not simply:

def get_singleton(x = SomeClass()):
return x

Or even:

singleton = SomeClass()

? Neither of the above provides anything above the last one, except
for late creation.

ChrisA
 
A

Asaf Las

Why not simply:
def get_singleton(x = SomeClass()):
return x
Or even:
singleton = SomeClass()
? Neither of the above provides anything above the last one, except
for late creation.

ChrisA

Actually need was to have some interface to running independent threads
to give same and once created object always.

For first - SomeClass's object will be created whenever there will be
call to get_singleton().
For second, again it is free to create it whenever someone (thread)
wish.

Hmmm, use case was to create persistent counter in multithreaded app
accessing single file where incrementing integer is stored.
When my imagination expanded it onto multiprocessing mess i ended up
using sqlite access to DB in exclusive transaction mode.
But this was not pythonic :)

Asaf
 
8

88888 Dihedral

Actually need was to have some interface to running independent threads

to give same and once created object always.



For first - SomeClass's object will be created whenever there will be

call to get_singleton().

For second, again it is free to create it whenever someone (thread)

wish.



Hmmm, use case was to create persistent counter in multithreaded app

accessing single file where incrementing integer is stored.

When my imagination expanded it onto multiprocessing mess i ended up

using sqlite access to DB in exclusive transaction mode.

But this was not pythonic :)



Asaf

In a high level language such as Python, functions and class initilizers
are the first class objects.

Don't you get the proof?
Everyting OOP is equivalent to everything functional but it is much trivial to debug by the designer
than the old grandma lisp.
 
N

Ned Batchelder

Actually need was to have some interface to running independent threads
to give same and once created object always.

For first - SomeClass's object will be created whenever there will be
call to get_singleton().

No, the value for a function argument's default is computed once when
the function is defined. Chris is right: get_singleton will always
return the same object.
For second, again it is free to create it whenever someone (thread)
wish.

Chris is right here, too: modules are themselves singletons, no matter
how many times you import them, they are only executed once, and the
same module object is provided for each import.
 
A

Asaf Las

is it possible to create singleton using construct below :

def singleton_provider(x = [None]):
if singleton_provider.__defaults__[0][0] == None:
singleton_provider.__defaults__[0][0] = SomeClass()
return singleton_provider.__defaults__[0][0]

Why not simply:
def get_singleton(x = SomeClass()):
return x
Or even:
singleton = SomeClass()
? Neither of the above provides anything above the last one, except
for late creation.
ChrisA

Hi Chris

Does it make sense to use former as template to make
singleton from any class as below, so instead of addressing
your second proposal using module name we can directly call
this one supplying class candidate for singleness as argument
to function?

class whatever():
def __init__(self):
self.one = 1
self.zero = 0

def singleton_provider(someclass, x = [None]):
if singleton_provider.__defaults__[0][0] == None:
singleton_provider.__defaults__[0][0] = someclass()
return singleton_provider.__defaults__[0][0]


print(id(singleton_provider(whatever)))

Thanks

Asaf
 
A

Asaf Las


and this one is about multiclass container function with
multithreading support:

import threading

def provider(cls, x = [threading.Lock(), {}]):
provider.__defaults__[0][0].acquire()
if not cls.__name__ in provider.__defaults__[0][1]:
provider.__defaults__[0][1][cls.__name__] = cls()
provider.__defaults__[0][0].release()
return provider.__defaults__[0][1][cls.__name__]


class whatever():
def __init__(self):
self.one = 1
self.zero = 0

class whatever1():
def __init__(self):
self.one = 1
self.zero = 0


print(id(provider(whatever)))
print(id(provider(whatever)))
print(id(provider(whatever1)))
print(id(provider(whatever1)))

could be there some hidden faults i missed?

/Asaf
 
J

Johannes Schneider

On 1/22/14 11:37 AM, Asaf Las wrote:
Chris is right here, too: modules are themselves singletons, no matter
how many times you import them, they are only executed once, and the
same module object is provided for each import.

I'm not sure, if this is the whole truth.

think about this example:

cat bla.py
a = 10

cat foo.py
from bla import a

def stuff():
return a

cat bar.py
from foo import stuff
print stuff()
a = 5
print stuff()

from bla import *
print a

python bar.py
10
10
10

here the a is coming from bla and is known in the global namespace. But
the value differs in stuff() and before/after the import statement. So
the instance of the module differs -> it cannot be a singelton.

bg,
Johannes

--
Johannes Schneider
Webentwicklung
(e-mail address removed)
Tel.: +49.228.42150.xxx

Galileo Press GmbH
Rheinwerkallee 4 - 53227 Bonn - Germany
Tel.: +49.228.42.150.0 (Zentrale) .77 (Fax)
http://www.galileo-press.de/

Geschäftsführer: Tomas Wehren, Ralf Kaulisch, Rainer Kaltenecker
HRB 8363 Amtsgericht Bonn
 
D

Dave Angel

Johannes Schneider said:
I'm not sure, if this is the whole truth.

think about this example:

cat bla.py
a = 10

cat foo.py
from bla import a

def stuff():
return a

cat bar.py
from foo import stuff
print stuff()
a = 5
print stuff()

from bla import *
print a

python bar.py
10
10
10

here the a is coming from bla and is known in the global namespace. But
the value differs in stuff() and before/after the import statement. So
the instance of the module differs -> it cannot be a singelton.

You're using 3 different variables here, each global to its own
module. If you really want to access the same object, you need to
reference it as bla.a. And ditch the from deal.

A from x import y. statement produces a new binding to the same
object. But since the object in your example is immutable, the
only way it can seem to change is by rebinding. If several names
are bound to the same object, rebinding one has no effect on the
others.
 
T

Terry Reedy

Johannes Schneider said:

This makes a a global in foo, bound to 10

This a refers to the global a in foo.

This bar.a is irrelevant to the behavior of stuff.

foo.a == 10

foo.a == 10

bla.a == 10

Twice

and is known in the global namespace.

There is no global namespace outside of modules.

No it does not.

and before/after the import statement.

foo.a does not change. bar.a is never used.

Nope. Each of the three module instances is constant. The bindings
within each could change, but there are no rebinding in the code above.
 
J

Johannes Schneider

thnx guys.

This makes a a global in foo, bound to 10


This a refers to the global a in foo.


This bar.a is irrelevant to the behavior of stuff.


foo.a == 10


foo.a == 10


bla.a == 10


Twice

and is known in the global namespace.

There is no global namespace outside of modules.


No it does not.

and before/after the import statement.

foo.a does not change. bar.a is never used.


Nope. Each of the three module instances is constant. The bindings
within each could change, but there are no rebinding in the code above.


--
Johannes Schneider
Webentwicklung
(e-mail address removed)
Tel.: +49.228.42150.xxx

Galileo Press GmbH
Rheinwerkallee 4 - 53227 Bonn - Germany
Tel.: +49.228.42.150.0 (Zentrale) .77 (Fax)
http://www.galileo-press.de/

Geschäftsführer: Tomas Wehren, Ralf Kaulisch, Rainer Kaltenecker
HRB 8363 Amtsgericht Bonn
 

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,079
Messages
2,570,574
Members
47,206
Latest member
Zenden

Latest Threads

Top