views:

231

answers:

2

I want

Stats.singleton.twitter_count += 1

and I thought I could do

class Stats:
    singleton_object = None

    @property
    @staticmethod
    def singleton():
        if Stats.singleton_object:
            return Stats.singleton_object
        Stats.singleton_object = Stats()
        return Stats.singleton()

But it throws an exception:

>>> Stats.singleton.a = "b"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'property' object has only read-only attributes (assign to .a)
+3  A: 

Static methods don't make sense in Python. That's because they do nothing that class methods can't, and are class methods much easier to extend in the future (when multiple class methods use each other etc).

What you need is simply a class method property.

I have a class method property from my code here. It is only read-only, that was all I needed (so the rest is an exercise to the reader):

class ClassProperty (property):
    """Subclass property to make classmethod properties possible"""
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

# how I would use it
class Stats:
    singleton_object = None
    @ClassProperty
    @classmethod
    def singleton(cls):
        if cls.singleton_object is None:
            cls.singleton_object = cls()
        return cls.singleton_object
kaizer.se
I don't think there is an answer to your 'exercise for the reader'; a data descriptor's __set__ method doesn't get called when you're doing a lookup on a class. The binding just gets changed.
Matt Anderson
+2  A: 

Singletons are pointless in python.

class A:
  class_var = object()

# two objects
a, b = A(), A()

# same var everywhere
assert a.class_var is b.class_var is A.class_var

Python's ints are differnt from simple objects, so it's not always that simple . But for your purposes, this seems to be enough:

class Stats:
    twitter_count = 0

Stats.twitter_count +=1
Stats.twitter_count +=1
assert Stats.twitter_count == 2
THC4k
I have a bit of a backstory, in that I want an AppEngine db.Model object to be a singleton (just one Stats object in the database). So I need to have at least one instance in memory.
Paul Tarjan
I don't get it. When you have a DB behind that, all instances already share the same state, the state of a row in your DB. Two instances might not be identical, but any ORM deserving that name will make sure that changing either will change the other too.
THC4k