People *depend* on None being a singleton (and are encouraged to do so),
when they use "is" as the test-for-Noneness.
Circular argument, though. If None weren't a singleton, people would
use == to test for Noneness. Since it's been guaranteed to be
optimized to a singleton, the comparison can also be optimized, but
it's still just an optimization, as can be seen with integers. In
CPython, you could test for small integer equality using 'is', but
since that optimization isn't guaranteed, neither is that code
pattern.
Except that if you do caching in the database connector, you would
certainly want the cache to be shared between all the users. There's no
right answer here. Each way has it's advantages and disadvantages. And
it would only be confusing if the documentation didn't spell out which
way it was doing it, leaving people to make (possibly wrong) assumptions.
Compare these:
# Style 1:
import magicsql
import othermodule
conn = magicsql.MagicSQL("127.0.0.1")
conn.set_parameter("foobar", True)
othermodule.do_stuff()
conn.query("select foo from bar")
# Style 2:
import magicsql
import othermodule
magicsql.connect("127.0.0.1")
magicsql.set_parameter("foobar", True)
othermodule.do_stuff()
magicsql.query("select foo from bar")
Suppose othermodule.do_stuff() does the same sort of calls except that
it sets parameter foobar to False. With Style 1, I would expect that
conn is independent of any connection object used by othermodule, and
it would be a major source of bugs (look at PHP's persistent
connections and how extremely careful you have to be with changing
*any* connection settings). But with Style 2, it's obvious that anyone
else importing magicsql and changing parameters will affect me.
That's why module-level functions are the clearer way to do this than
singleton classes.
Except when it doesn't. Singleton-ness of modules depends on the names
under which they were imported. Symlinks, for example, can fool the
import machinery.
$ ls -l s1 s2
lrwxrwxrwx 1 roy roy 1 Feb 13 10:13 s1 -> s
lrwxrwxrwx 1 roy roy 1 Feb 13 10:13 s2 -> s
$ ls -l s
total 12
-rw-rw-r-- 1 roy roy 0 Feb 13 10:13 __init__.py
-rw-rw-r-- 1 roy roy 101 Feb 13 10:14 __init__.pyc
-rw-rw-r-- 1 roy roy 9 Feb 13 10:12 singleton.py
-rw-rw-r-- 1 roy roy 123 Feb 13 10:14 singleton.pyc
False
Sure, they're not a guarantee. And if you fork a subprocess, then you
have copies of the singleton, too. That's not the point here. If you
have two modules and each one types "import random", you would not be
surprised to learn that the name "random" in each is bound to the
exact same random, and that they effectively share state. If you're
calling random.random(), and then you call another module which
imports random and calls random.random(), you don't complain that your
sequence of random numbers was disrupted.
But if you were to get yourself a random.Random() instance and someone
else does the same, then the style of code makes it *look like* you
should be working with independent objects. And in the case of the
random module, that is exactly what happens. Instantiate? Separate.
Module-level functions? Shared.
ChrisA