473,320 Members | 2,020 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Singleton

Hi,

I've been trying to get some sort of singleton working in python, but
I struggle a bit and I thought I'd ask for advice.

The first approach was simply to use a module, and every variable in
it will be seen by all who import the module.
That works in some cases, but not if I have the following structure:

one/
__init__.py
mod1.py
run.py
two/
__init__.py
mod2.py

run.py looks like this:
#!/usr/bin/env python
import mod1
print mod1.number
import two.mod2
print two.mod2.number

mod1.py looks like this:
import random
number=random.randint(0,100)

mod2.py looks like this
import one.mod1
number = one.mod1.number

PYTHONPATH is set to the directory containing the 'one' and 'two'
directories.

Now when I run the 'run.py', it will print two different numbers.
sys.modules tells me that 'mod1' is imported as both 'one.mod1' and
'mod1', which explains the result.

Looking at:
http://aspn.activestate.com/ASPN/Coo...n/Recipe/52558
I find a singleton class, but it has the same problem. If it's
imported in two different ways, I have not a singleton but a ...
'doubleton' or something.

It is possible to solve this by always importing with the complete
path like 'one.mod1', even when inside the 'one' directory, but that's
an error waiting to happen.

So how do people solve this? Is there an obvious way that I missed?

I'm thankful for any advice you might provide.

Oct 10 '07 #1
12 1717
On Oct 10, 5:36 am, pythoncuri...@gmail.com wrote:
Hi,

I've been trying to get some sort of singleton working in python, but
I struggle a bit and I thought I'd ask for advice.

The first approach was simply to use a module, and every variable in
it will be seen by all who import the module.
That works in some cases, but not if I have the following structure:

one/
__init__.py
mod1.py
run.py
two/
__init__.py
mod2.py

run.py looks like this:
#!/usr/bin/env python
Well, here's your problem. Your main script is inside a package: that
is what's causing the namespace difficulties you're seeing.

I highly suggest you not do that. A better ideas is to create a small
script in the project root that imports run.py, like this:

#!/usr/bin/env python
from one import run
[continuing with run.py]
import mod1
print mod1.number
It's is only tangentially related to your problem, but this usage is
deprecated.

Importing a file in the same package using "import modl" instead of
"from one import mod1" is called an impicit relative import (well,
actually in this case it isn't a relative import--more on that later--
but you seem to have intended it as a relative import). Implicit
relative imports are scheduled to be removed from a future release of
Python.

You should use either an absolute import:

from one import mod1

Or an explicit relative import in Python 2.5 or above:

from . import mod1
See PEP 328.
[continuing again with run.py]
import two.mod2
print two.mod2.number

mod1.py looks like this:
import random
number=random.randint(0,100)

mod2.py looks like this
import one.mod1
number = one.mod1.number

PYTHONPATH is set to the directory containing the 'one' and 'two'
directories.

Now when I run the 'run.py', it will print two different numbers.
sys.modules tells me that 'mod1' is imported as both 'one.mod1' and
'mod1', which explains the result.
Here's the problem: the main script is NOT executed within the package
"one". A file's presence in a package directory is not sufficient for
it to be part of the package: you actuatlly have to import the file
through that package.

When you ran run.py, the Python interpreter did not import the file
via the "one" package. It loaded the file, compiled it, and ran it,
but as a standalone file, not as part of a package.

Then, when you imported "mod1" from "run.py", it only saw that mod1.py
was a file in the same directory. So it imported it as a regular
module, not a submodule of a package.

Now, when mod2 imported mod1, it went through the package "one" to
import it. Therefore, it considered mod1 to be part of the package
"one", and so imported it as a submodule of "one".

Looking at:http://aspn.activestate.com/ASPN/Coo...n/Recipe/52558
I find a singleton class, but it has the same problem. If it's
imported in two different ways, I have not a singleton but a ...
'doubleton' or something.

It is possible to solve this by always importing with the complete
path like 'one.mod1', even when inside the 'one' directory, but that's
an error waiting to happen.
I've been doing it for a few years; I haven't had a problem. If
you're concerned, you can add "from __future__ import
absolute_imports" to your files to catch any lapses.

So how do people solve this? Is there an obvious way that I missed?

I'm thankful for any advice you might provide.
Just keep your main scripts out of the package directories and you'll
be fine.

Carl Banks

Oct 10 '07 #2
Spring Python (http://springpython.python-hosting.com) offers a
singleton solution. You can mark up function calls to only be called
the first time, i.e. as singletons. The results are cached inside the
Spring Python IoC container, so the next time the function is called,
it returns the cached copy. Prototypes bypass the caching, and instead
allow the function to be called everytime. This also support the idea
of prototype functions contain references to singleton objects.

from springpython.context import *

class MyContainer(DecoratorBasedApplicationContext):
def __init__(self):
DecoratorBasedAppicationContext.__init__(self)

@component(scope.SINGLETON) # You can leave off the argument, since
scope.SINGLETON is the default)
def singletonComponent(self):
return ["There can be only one!"]

@component(scope.PROTOTYPE):
def prototypeComponent(self):
return ["I think I'm a clone now. There's another one of me
always hangin' around!"]

if __name__ == "__main__":
appContext = MyContainer()

obj1 = appContext.singletonComponent()
obj2 = appContext.singletonComponent()
if obj1 == obj2:
print "These are the same object"
else:
print "Something is wrong!"

obj3 = appContext.prototypeComponent()
obj4 = appContext.prototypeComponent()
if obj1 != obj2:
print "These are different instances of the function call."
else:
print "These shouldn't be the same!"

See also http://springpython.python-hosting.c...rsionOfControl
and http://springpython.python-hosting.c...icationContext.

Oct 10 '07 #3
On Oct 10, 9:34 am, OnCallSupport...@gmail.com wrote:
Spring Python (http://springpython.python-hosting.com) offers a
[snip spam]
Too bad your bot can't be bothered to read the post it would have
known the singleton wasn't the problem here.
Carl Banks

Oct 10 '07 #4
On Wed, 10 Oct 2007 09:36:56 +0000, pythoncurious wrote:
So how do people solve this? Is there an obvious way that I missed?
Mostly by avoiding singletons. Why do you need only one instance? Perhaps
you should consider the Borg pattern instead.

http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531

--
Steven
Oct 10 '07 #5
On Oct 10, 9:39 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
On Wed, 10 Oct 2007 09:36:56 +0000, pythoncurious wrote:
So how do people solve this? Is there an obvious way that I missed?

Mostly by avoiding singletons. Why do you need only one instance? Perhaps
you should consider the Borg pattern instead.

http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531

That wouldn't help. In the OP's case, it would create two borgs. Did
anyone actually read the OP's post? Or is this just an opportunity to
pimp libraries and bicker about style?
Carl Banks

Oct 10 '07 #6
py***********@gmail.com writes:
Now when I run the 'run.py', it will print two different numbers.
sys.modules tells me that 'mod1' is imported as both 'one.mod1' and
'mod1', which explains the result.
If I were you, I'd make sure that the module duplicate problem is
resolved first, for example by putting run.py somewhere outside one/.
Then the singleton problem disappears as well.
It is possible to solve this by always importing with the complete
path like 'one.mod1', even when inside the 'one' directory, but
that's an error waiting to happen.
Is it, really? As far as I can tell, Python handles that case rather
robustly. For example:

$ mkdir one
$ touch one/__init__.py
$ touch one/mod1.py one/mod2.py
$ echo 'import mod2' one/mod1.py
$ python
Python 2.5.1 (r251:54863, May 2 2007, 16:56:35)
[GCC 4.1.2 (Ubuntu 4.1.2-0ubuntu4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>import one.mod1
import sys
sorted(sys.modules)
['UserDict', '__builtin__', '__main__', '_codecs', '_sre', '_types', 'codecs', 'copy_reg', 'encodings', 'encodings.aliases', 'encodings.codecs', 'encodings.encodings', 'encodings.types', 'encodings.utf_8', 'exceptions', 'linecache', 'one', 'one.mod1', 'one.mod2', 'os', 'os.path', 'posix', 'posixpath', 're', 'readline', 'rlcompleter', 'signal', 'site', 'sre_compile', 'sre_constants', 'sre_parse', 'stat', 'sys', 'types', 'warnings', 'zipimport']

Although mod1 imports mod2 simply with "import mod2", the fact that
mod1 itself is imported as part of "one" is respected. As a result,
mod2 is imported as "one.mod2", exactly as if it were imported from
outside the "one" package.

run.py is an exception because it is started directly using "python
run.py", so it never gets the information that it's supposed to be
part of a package. To fix the problem, all you need to do is make
sure that executable scripts such as run.py are either placed safely
outside the package, or that they take care to always use absolute
imports, such as "import one.mod1" instead of "import mod1". Placing
them outside the package is a good example of preventing an error
waiting to happen, like the one you hinted at.
Oct 10 '07 #7
On Wed, 10 Oct 2007 06:57:15 -0700, Carl Banks wrote:
On Oct 10, 9:39 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
>On Wed, 10 Oct 2007 09:36:56 +0000, pythoncurious wrote:
So how do people solve this? Is there an obvious way that I missed?

Mostly by avoiding singletons. Why do you need only one instance?
Perhaps you should consider the Borg pattern instead.

http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531


That wouldn't help. In the OP's case, it would create two borgs.
Two borgs, or two million, the whole point of using borgs is that it
doesn't matter.

Did
anyone actually read the OP's post? Or is this just an opportunity to
pimp libraries and bicker about style?
Well, let's see now... the OP says:

"I've been trying to get some sort of singleton working in python, but
I struggle a bit and I thought I'd ask for advice."

If we take each word to have it's normal English meaning, then the OP is
struggling to get a singleton working correctly in Python. The way I
solve that problem is to deftly side-step it by not using a singleton.

("Doctor, it hurts when I do this."
"Then don't do it.")

Of course, if there is some other meaning to the OP's post, then possibly
I've completely misunderstood it. Would you mind telling me what you've
seen that the rest of us haven't?

--
Steven.
Oct 10 '07 #8
Steven D'Aprano wrote:
On Wed, 10 Oct 2007 06:57:15 -0700, Carl Banks wrote:
>On Oct 10, 9:39 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
>>On Wed, 10 Oct 2007 09:36:56 +0000, pythoncurious wrote:
So how do people solve this? Is there an obvious way that I missed?

Mostly by avoiding singletons. Why do you need only one instance?
Perhaps you should consider the Borg pattern instead.

http://aspn.activestate.com/ASPN/Coo...n/Recipe/66531


That wouldn't help. In the OP's case, it would create two borgs.

Two borgs, or two million, the whole point of using borgs is that it
doesn't matter.
It does matter where the classes live (module-wise). Which is the problem
the OP had, borg or not to borg.

class Borg(object):
__shared_state = {}

def __init__(self):
self.__dict__ = self.__shared_state
if __name__ == "__main__":
import test
mainBorg = Borg()
mainBorg.a = 100
testBorg = test.Borg()
testBorg.a = 200
print mainBorg.a
print testBorg.a

Run this as this:

droggisch@ganesha:/tmp$ ll *py
-rw-r--r-- 1 droggisch 298 2007-10-10 17:30 test.py
droggisch@ganesha:/tmp$ python test.py
100
200
You will see that there are _two_ different Borg-Cubes, as the output
indicates. This has hit me more than once, and Carl Banks pointed that
error out to the OP.

And if you'd follow your own advice of " take each word to have it's normal
English meaning," then the OP is not

"struggling to get a singleton working"

but struggling to get "some sort of singleton working", as you cite
yourself, and first tried to implement his needs using no singleton-recipe
(or borg pattern) but a module:

"""
The first approach was simply to use a module, and every variable in
it will be seen by all who import the module.
That works in some cases, but not if I have the following structure:
"""

Which didn't work out for the same reason his singleton approach didn't work
and your beloved Borg-pattern doesn't as well.

Diez

Oct 10 '07 #9
On Oct 10, 11:18 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
Of course, if there is some other meaning to the OP's post, then possibly
I've completely misunderstood it. Would you mind telling me what you've
seen that the rest of us haven't?
I read far enough to see that OP had mischaracterized the problem and
that it wasn't a problem with singletons at all; it was a problem with
importing.

And that it would still manifiest itself with borgs.
Carl Banks

Oct 10 '07 #10
On Wed, 10 Oct 2007 09:52:26 -0700, Carl Banks wrote:
On Oct 10, 11:18 am, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.auwrote:
>Of course, if there is some other meaning to the OP's post, then
possibly I've completely misunderstood it. Would you mind telling me
what you've seen that the rest of us haven't?

I read far enough to see that OP had mischaracterized the problem and
that it wasn't a problem with singletons at all; it was a problem with
importing. And that it would still manifiest itself with borgs.
Fair enough, thanks to Diez's example, I see that now.

The way I read the OP's post, he was only having problems *because* of
the requirement "I must have a singleton". Change the requirement to "I
don't need a singleton" and maybe the problem goes away, yes? And if not,
then at least it becomes obvious that the problem is nothing to do with
singletons.

--
Steven.
Oct 11 '07 #11
On Wed, 10 Oct 2007 17:37:53 +0200, Diez B. Roggisch wrote:
>Two borgs, or two million, the whole point of using borgs is that it
doesn't matter.

It does matter where the classes live (module-wise). Which is the
problem the OP had, borg or not to borg.

Gotcha. Thanks for the demonstration code, that makes it clear.

[snip]

You will see that there are _two_ different Borg-Cubes, as the output
indicates. This has hit me more than once, and Carl Banks pointed that
error out to the OP.

And if you'd follow your own advice of " take each word to have it's
normal English meaning," then the OP is not

"struggling to get a singleton working"

but struggling to get "some sort of singleton working", as you cite
yourself, and first tried to implement his needs using no
singleton-recipe (or borg pattern) but a module:
Using modules *is* a recipe for getting singletons, as the OP clearly
understood.

Which didn't work out for the same reason his singleton approach didn't
work and your beloved Borg-pattern doesn't as well.
It's not my beloved Borg-pattern. My original post asked: "Why do you
need only one instance?" and suggested that *perhaps* he should
*consider* an alternative. Sheesh. It's not like I said that the Borg
solves every problem every time.

--
Steven.
Oct 11 '07 #12
Hi again,

Just wanted to say thanks.
I now see that I misunderstood where the problem was and I got
useful information about how importing stuff works.

My problem is solved and I'm grateful for your help.
Oct 16 '07 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Tim Clacy | last post by:
Is there such a thing as a Singleton template that actually saves programming effort? Is it possible to actually use a template to make an arbitrary class a singleton without having to: a)...
10
by: E. Robert Tisdale | last post by:
Could somebody please help me with the definition of a singleton? > cat singleton.cc class { private: // representation int A; int B; public: //functions
1
by: Jim Strathmeyer | last post by:
So I'm trying to implement a singleton template class, but I'm getting a confusing 'undefined reference' when it tries to link. Here's the code and g++'s output. Any help? // singleton.h ...
3
by: Alicia Roberts | last post by:
Hello everyone, I have been researching the Singleton Pattern. Since the singleton pattern uses a private constructor which in turn reduces extendability, if you make the Singleton Polymorphic...
7
by: Ethan | last post by:
Hi, I have a class defined as a "Singleton" (Design Pattern). The codes are attached below. My questions are: 1. Does it has mem leak? If no, when did the destructor called? If yes, how can I...
3
by: Harry | last post by:
Hi ppl I have a doubt on singleton class. I am writing a program below class singleton { private: singleton(){}; public: //way 1
5
by: Pelle Beckman | last post by:
Hi, I've done some progress in writing a rather simple singleton template. However, I need a smart way to pass constructor arguments via the template. I've been suggested reading "Modern C++...
6
by: Manuel | last post by:
Consider the classic singleton (from Thinking in C++): ----------------------------------------------------- //: C10:SingletonPattern.cpp #include <iostream> using namespace std; class...
3
weaknessforcats
by: weaknessforcats | last post by:
Design Pattern: The Singleton Overview Use the Singleton Design Pattern when you want to have only one instance of a class. This single instance must have a single global point of access. That...
3
by: stevewilliams2004 | last post by:
I am attempting to create a singleton, and was wondering if someone could give me a sanity check on the design - does it accomplish my constraints, and/or am I over complicating things. My design...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.