使用哪个:类变量与classmethod?

时间:2014-06-09 20:01:19

标签: python

作为下面的玩具示例,它们都创建了相同的类(尽管一个使用Foo.spam()而另一个使用Foo.spam来获取值)。我的问题是,选择一个而不是另一个的标准是什么?如果需要经常访问spam,那么由于函数开销,最好使用第二类实现吗?还要别的吗?

class Foo(object):
    def __init__(self, a):
        self.a = "init"
    @classmethod
    def spam(cls, value=2):
        return value + 1
Foo.spam() # -> 3
Foo.spam(3) #-> 4

class Foo(object):
    spam = 3
    def __init__(self, a):
        self.a = "init"
Foo.spam  #-> 3
Foo.spam = 4
Foo.spam  #-> 4

2 个答案:

答案 0 :(得分:3)

我不认为你想要完成的任何事情都是正确的(为类属性分配一个默认值)。你为什么不这样做呢?

class Foo(object):
    def __init__(self, a = 'init'):
        self.a = a
        self.spam = 2

然后:

>>> a_foo = Foo()
>>> a_foo.spam
2
>>> a_foo.spam = 3
>>> a_foo.spam
3

如果通过静态类属性(第二个示例)执行此操作,则可以根据您分配/访问它的方式获得非常不同的行为:

class Foo(object):
    spam = 2
    def __init__(self, a = 'init'):
        self.a = a

然后:

>>> a_foo1 = Foo()
>>> a_foo2 = Foo()
>>> a_foo1.spam
2
>>> a_foo2.spam
2
>>> Foo.spam = 3
>>> a_foo1.spam
3
>>> a_foo2.spam
3

# But now they'll diverge
>>> a_foo1.spam = 5
>>> a_foo1.spam
5
>>> a_foo2.spam
3
>>> Foo.spam = 2
>>> a_foo1.spam
5
>>> a_foo2.spam
2

如果您尝试将其设置为修改spam的任何实例副本,则修改所有 实例' s spam的副本,您使用的属性与静态属性相结合

class Foo(object):
    _spam = 2
    def __init__(self, a = 'init'):
        self.a = a

    @property
    def spam(self):
        return Foo._spam

    @spam.setter
    def spam(self, value)
        Foo._spam = value

>>> a_foo1 = Foo()
>>> a_foo2 = Foo()
>>> a_foo1.spam
2
>>> a_foo2.spam
2
>>> a_foo1.spam = 3
>>> a_foo2.spam
3

虽然这种单例属性行为有点危险,并且可能被某些人视为反模式,因为类的大多数用户不希望修改一个实例的属性来修改所有实例'属性。你肯定需要有一个很好的理由这样做。

答案 1 :(得分:2)

如果方法没有做任何事情,只是返回属性值,只需使用属性。

但是,你的例子很奇怪,因为你传递了你想要的值。如果您只想要数字3,则无需使用Foo.spam(3) Foo.spam = 3;只需使用数字3。