Python:@staticmethod和@property

时间:2009-11-08 18:52:31

标签: python singleton properties

我想要

Stats.singleton.twitter_count += 1

我想我能做到

class Stats:
    singleton_object = None

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

但它引发了一个例外:

>>> 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)

6 个答案:

答案 0 :(得分:60)

用户kaizer.se就原始问题而言已经开始了。我在简单性方面更进了一步,所以它现在只需要一个装饰器:

class classproperty(property):
    def __get__(self, cls, owner):
        return classmethod(self.fget).__get__(None, owner)()

用法:

class Stats:
    _current_instance = None

    @classproperty
    def singleton(cls):
        if cls._current_instance is None:
            cls._current_instance = Stats()
        return cls._current_instance

如上所述,这种创建单身的方式并不是一个好的设计模式;如果必须这样做,元类工厂是一个更好的方法。我对于一个阶级财产的前景感到很兴奋,所以,就是这样。

答案 1 :(得分:3)

静态方法在Python中没有意义。那是因为他们什么都不做,类方法不能,并且将来更容易扩展类方法(当多个类方法互相使用时等)。

您需要的只是一个类方法属性。

我的代码中有一个类方法属性。它只是只读的,这就是我所需要的(所以剩下的就是读者的练习):

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

答案 2 :(得分:3)

单人在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的int与简单的object不同,所以并不总是这么简单。但就你的目的而言,这似乎已经足够了:

class Stats:
    twitter_count = 0

Stats.twitter_count +=1
Stats.twitter_count +=1
assert Stats.twitter_count == 2

答案 3 :(得分:1)

跟进KyleAlanHale所写的内容:

他的榜样很有效,直到你尝试做:

Stats.singleton = 5

这不会给你一个错误,它会覆盖这个功能,所以当你输入下一个

single = Stats.singleton
print single

你会得到

5

我认为在没有@classproperties装饰的情况下,你最好使用Kyle的答案。

答案 4 :(得分:0)

我认为这是实现单例的最佳方法:

class Foo: 
    _static_self = None;
    # __new__ takes object creation out of user's hands
    def __new__(cls, *args, **kwargs): 
        if not cls._static_self:
            cls._static_self = super().__new__(cls, *args, **kwargs);
        vars(cls._static_self).clear(); # wipe old state
        return cls._static_self;

    @property
    def a_property(self):
        return 'a value' # or a real variable...

请注意,the object is (re)initialized automatically(带有适当的参数)由__new__()返回

您还可以结合使用__new____init_subclass__()以干净的pythonic方式实现工厂模式。

答案 5 :(得分:0)

我想给出一个Python代码段来说明属性静态方法的工作方式会有所帮助。

它们都是实现 __ get __ __ set __

的描述符

属性是数据描述符

class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

静态方法是一个非数据描述符

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f