classes

Steven Taschuk staschuk at telusplanet.net
Sun Jul 20 20:04:20 CEST 2003


Quoth Pablo:
> [cut]
> >> 2) how to declare a static method
> > 
> >     class HasStaticMethod:
> >        def method(arg0, arg1):  # note the lack of "self"
> >           # do something with arg0 and arg1
> >        method = staticmethod(method)
> 
> That's not exactly what I wanted.
  [...]
> but Python does not allow to invoke any class method without providing an
> instance of the class object

Sure it does.  Allowing that is the purpose of the "staticmethod"
call in Dan's example.

Try it yourself:

    >>> class HasStaticMethod(object):
    ...     def mystaticmethod(x, y):
    ...         print x, y
    ...     mystaticmethod = staticmethod(mystaticmethod)
    ... 
    >>> HasStaticMethod.mystaticmethod(3, 4)
    3 4

No instance of HasStaticMethod exists here.

  [...]
> So my problem would be solved if I could create a class which would be
> seen only in its module (something like private class). Then I could
> create an object and simply use it across my application.
  [...]
> Is it possible to create a class and forbid its use outside its module?

No, not really.  (There's a philosophical reason: Java encourages
the attitude that other programmers can't be trusted to use your
code correctly, while Python encourages the attitude that other
programmers know what they're doing.  Thus there's not a lot of
mechanisms in Python to forbid other programmers from doing things
with your code.)

For the particular problem you're interested in -- singletons --
here are a few approaches:

First, use __new__ trickery:

    _the_instance = None
    class MySingleton(object):
        def __new__(self):
            global _the_instance
            if _the_instance is None:
                _the_instance = object.__new__(self)
            return _the_instance

Example use:

    >>> x = MySingleton()
    >>> y = MySingleton()
    >>> x is y  # same object!
    True

In this approach, users create instances of MySingleton as they
would for any other class (rather than by calling a getInstance
classmethod) -- that action just happens to return the same object
always.

One gotcha with this approach can be observed by adding

    def __init__(self):
        print 'running __init__ on instance %s' % id(self)

Then we see

    >>> x = MySingleton()
    running __init__ on instance 1075795852
    >>> y = MySingleton()
    running __init__ on instance 1075795852
    >>> x is y
    True

As shown, each "instantiation" runs __init__ on the single
instance again.  If you have initialization which should occur
only when the single instance is actually created:

    _the_instance = None
    class MySingleton(object):
        def __new__(self):
            global _the_instance
            if _the_instance is None:
                _the_instance = object.__new__(self)
                _the_instance._my_init()
            return _the_instance
        def _my_init(self):
            pass  # one-time initialization here

(Another possible issue with this approach arises when subclassing
MySingleton.  Details left as an exercise.)

Second approach: Use a metaclass.  See
    <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/102187>

Third: forget about singletons and use a Borg.  See
    <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531>
(With Borgs, multiple instances may exist, but they share state.)

Fourth: rethink the idea that a database connection should be a
singleton.  See
    <http://c2.com/cgi/wiki?SingletonsAreEvil>
and linked pages for discussion on the merits of singletons.

-- 
Steven Taschuk                                7\ 7'Z {&~         .
staschuk at telusplanet.net                        Y r          --/hG-
                                            (__/ )_             1^1`





More information about the Python-list mailing list