Pythonic方式如何初始化属性或特性?

4 投票
3 回答
5774 浏览
提问于 2025-04-17 12:37

Python支持类属性、实例属性和属性。

from time import ctime, sleep

class MyClass(object):
    A = ctime()            # class attribute
    def __init__(self):
        self.B = ctime()   # instance attribute
        self._C = None

    @property
    def C(self):           # property
        if self._C is None:
            self._C = ctime()
        return self._C
    @C.setter
    def C(self, c):
        self._C

对于一个不了解MyClass实现的人来说,A、B和C表现得很相似:

sleep(2)
myObject = MyClass()
sleep(2)
print myObject.A         # prints time module was initialized
print myObject.B         # prints time instance was created, 2 sec later
print myObject.C         # prints time this line was called, 2 sec later
myObject.A = 'foo'       # myObject.A is now an instance attribute
myObject.B = 'foo'       # myObject.B is still an instance attribute
myObject.C = 'foo'       # myObject.C is still an (instance) property
print myObject.A         # prints 'foo'
print myObject.B         # prints 'foo'
print myObject.C         # prints 'foo'

根据我在这里得到的回答,我明白了以下几点:第一次打印myObject.A时,myObject.A等于myObject.__Class__.A,也就是MyClass.A。第二次打印myObject.A时,它就不再是myObject.__Class__.A了。明白了。

在上面的例子中,ctime()只是用来说明A、B和C之间的区别。现在假设我们使用一个不可变的常量来代替:

class MyClass(object):
    A = 'bar'               # class attribute
    def __init__(self):
        self.B = 'meta'     # instance attribute
        self._C = None

    @property
    def C(self):            # property
        if self._C is None:
            self._C = 'foobar'
        return self._C
    @C.setter
    def C(self, c):
        self._C = c

myObject = MyClass()

myObject.A仍然是类属性MyClass.A,而myObject.B是实例属性,myObject.C是一个属性。它们都完全符合我的需求。它们都有一个默认值,我也可以给它们赋其他值。那么我应该使用哪种风格,A、B还是C呢?

3 个回答

1

看起来有两种方式来创建简单的属性或特性。

其实这根本不是“方式”,只是做了一件事:赋值。

它们的效果是不同的。

在Python中,逻辑规则是这样的:在class块中声明的东西属于这个类。因此,A是这个类的一个属性(大致相当于在C++、Java或C#中声明的static属性)。而B是每个实例的一个属性,当实例运行__init__时会自动生成。

至于你的更新,我不太明白你想问什么。试着用真实的名字,而不是'A',并解释一下你的使用场景(也就是你为什么想要做这个)。

1

这要看你希望什么时候进行初始化,以及你想要什么样的实例。

  • 如果你希望这个属性只有一个实例(也就是一个值),并且这个值在所有类的实例之间共享,那就用类属性。
  • 如果你希望每个类的实例都有一个不同的属性值,那就用实例属性。

顺便提一下,你的代码示例中使用的是属性,而不是特性。

我不太明白你对问题的更新。你可能需要退一步,解释一下你根本的问题是什么。

2

初始化一个常量类属性的最佳方式是在类定义的时候直接设置。

从问题中的代码来看,似乎对如何通过实例对象访问类属性有些困惑。

需要注意的是,在实例对象中,你可以通过名字来访问类属性,因为当在内部字典中找不到某个属性时,系统会继续在类的字典中查找。也就是说,如果instance.A不存在,系统会返回instance.__class__.A,前提是它存在。

不过,当在对象实例中创建了一个属性时,这个类属性就会被遮蔽。也就是说,instance.A = <value>会创建一个新的实例属性,下次你访问instance.A时,就会返回<value>。不过,你仍然可以通过instance.__class__.A来获取类属性。

撰写回答