8

我有一个具有许多属性的类。有人可以澄清设置属性(如下面的 a、b、c 和 x、y、z)之间的区别。我知道,如果您要输入参数,它们显然必须在init中,但是,仅用于设置一些默认变量,这是首选,优缺点是什么。

class Foo(object):
    a = 'Hello'
    b = 1
    c = False
    def __init__(self):
        self.x = 'World'
        self.y = 2
        self.z = True
4

4 回答 4

8

变量abc是类变量。它们在首次创建类时被评估和设置一次。变量xyz是实例变量,只要实例化该类的对象,就会对其进行评估和设置。

通常,如果类的每个实例都将使用相同的值,则使用类变量,并且只需要计算一次。您将实例变量用于该类的每个实例将不同的变量。

您可以通过实例变量语法访问类变量self.a,但有问题的对象在类的所有实例之间共享。这在使用不可变数据类型(如整数或字符串)时影响不大,但在使用可变数据类型(如列表)时,追加到self.a会导致所有实例看到新追加的值。

IDLE 中的一些示例可能有助于理解这一点:

>>> class Foo(object):
    a = 'Hello'
    b = []
    def __init__(self):
        self.y = []

>>> instance_1 = Foo()
>>> instance_2 = Foo()
>>> instance_1.a
'Hello'
>>> instance_2.a
'Hello'
>>> instance_1.a = 'Goodbye'
>>> instance_1.a
'Goodbye'
>>> instance_2.a
'Hello'
>>> instance_1.b
[]
>>> instance_2.b.append('12345')
>>> instance_1.b
['12345']
>>> instance_2.y
[]
>>> instance_2.y.append('abcde')
>>> instance_2.y
['abcde']
>>> instance_1.y
[]
于 2012-09-13T00:15:48.883 回答
6

使用类属性为您打算成为特定于实例的数据提供默认值的主要缺点是,默认值将在类的所有实例之间共享,直到值被更改。例如:

class Foo(object):
    a = []

foo1 = Foo()
foo2 = Foo()

foo1.a.append(123)

foo1.a # [123]
foo2.a # [123]

但是,以下将按预期工作:

class Bar(object):
    a = 123    

bar1 = Bar()
bar2 = Bar()

bar1.a = 456

bar2.a # 123

为避免在使用此技术时出现此问题,您应该只使用它来设置不可变值的默认值。(例如数字、字符串、元组……)

Python 以这种方式运行的原因是,当您使用以下命令访问属性时:

foo.bar

然后bar是先在对象中查找foo。如果在对象中找不到名称 in (即 in foo.__dict__),则在该对象的类型中查找名称。例如,这种机制是方法查找工作方式的一部分。(如果您查看__dict__对象的 ,您会注意到它的方法不存在。)

其他小问题是,当它们打算特定于实例时,这会通过类型对象公开默认值;并且如果您有任何默认值,它将混合特定于类的属性(如常量)的定义。前者的推论是,这将允许您稍后通过分配给类属性为尚未更改值的所有对象重新定义默认值。(这可能有用,也可能令人困惑;对可变“全局”变量的预防措施同样适用。)

于 2012-09-13T00:43:18.117 回答
2

正如您声明的那样,a、b 和 c 将可用,而无需创建 Foo 的实例。
例如,你可以说:

Foo.a = "Goodbye"

相反,在创建 Foo 的实例之前不会创建 x、y 和 z,它们特定于该实例:

bar = Foo()
bar.x = 42
于 2012-09-13T00:19:00.463 回答
1

这个问题被问了无数遍……

a,b,c是在所有实例之间共享的类变量,一个很好的用途将是一个计数器来计算已创建的此类的所有出现次数,x,y,z是属于该单个实例的实例变量,因此self用于设置它们......

请注意,您实际上可以像self.a = 3这样隐藏类变量并不会改变a而是隐藏它......并且让一些人感到惊讶。

演示:

>>> class Foo(object):
...     a = 3
...     def __init__(self):
...         self.x = 6
... 
>>> Foo.a
3
>>> b = Foo()
>>> b.a = 5
>>> b.a
5
>>> Foo.a
3
>>> b.a
5
>>> Foo.a = 9
>>> Foo.a
9
>>> b.a
5
>>> c = Foo()
>>> c.a
9
于 2012-09-13T00:39:25.197 回答