定义具有许多属性的Python类 - 样式

jbb*_*med 8 python styles class

我有一个具有许多属性的类.有人可以澄清设置属性如下面的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
Run Code Online (Sandbox Code Playgroud)

Joe*_* C. 7

变量a,bc是类变量.首次创建类时,它们会被评估并设置一次.变量x,yz是实例变量,其被评估并且每当那个类的一个对象被实例化设置.

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

您可以通过实例变量语法访问类变量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
[]
Run Code Online (Sandbox Code Playgroud)


mil*_*ose 5

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

class Foo(object):
    a = []

foo1 = Foo()
foo2 = Foo()

foo1.a.append(123)

foo1.a # [123]
foo2.a # [123]
Run Code Online (Sandbox Code Playgroud)

但是,以下内容可以正常工作:

class Bar(object):
    a = 123    

bar1 = Bar()
bar2 = Bar()

bar1.a = 456

bar2.a # 123
Run Code Online (Sandbox Code Playgroud)

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

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

foo.bar
Run Code Online (Sandbox Code Playgroud)

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

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