类变量的行为,当它不在__init__时

时间:2014-04-10 09:28:29

标签: python oop

我有以下名为MyClass的类:

 def __init__(self, config):
        self.response = Response(config)
        self.utility = Utility()
        self.listl = {}

它有以下方法:

 def findSt(self, lv):      
        dvp = self.listl
        if lv not in dvp:
            raise Exception("ERROR: ....", lv)
        else:
             ...

在我的主代码中,我使用同一个类的另一个方法(getvalues)为self.listl提供正确的值,即:

    myobject = MyClass(config)
    myobject.listl = myobject.getvalues()
    lr = []
    for lv in lvs:
        lr.append(myobject.findSt(lv))   

这有效,虽然我不确定这是否正确。我问的原因是因为如果我在主代码中执行以下拼写错误:

myobject.listL = myobject.getvalues()

没有错误提出!当然,在这种情况下myobject.listl没有正确的运行时值,因此它不起作用,但为什么我可以创建一个不在__init__的变量?

2 个答案:

答案 0 :(得分:1)

出于同样的原因,您可以设置myobject.listl - 您可以在任何地方设置任何实例的任何属性*,__init__中设置的属性在任何方面都不是特殊的。关于__init__唯一特别之处在于它是在创建新实例时自动调用的。

这并不意味着你必须使用它,通常最好不要在课外设置这些属性,我更喜欢有类似的方法

def setvalues(self):
    self.listl = self.getvalues()

左右。一般来说,你需要小心,因为你有一个mutable属性,如果一些外部代码仍然拥有对旧self.listl的引用呢?然后该代码不会更改旧列表。这样就可以了:

def setvalues(self):
    self.listl[:] = self.getvalues()

不重新设置listl属性,而只重新设置其中的值。但这是一个完全不同的讨论。

*:有一些例外,例如在C中实现的类,或者定义了__slots__的类,但这些是罕见的例外。

答案 1 :(得分:1)

用户定义的类实例可以在运行时添加/删除属性:

>>> class A(object): pass
... 
>>> a = A()
>>> a.something = 1   #no error. Now a has a new something attibute
>>> 

虽然内置类型通常不允许这样做:

>>> a = object()
>>> a.something = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'something'

在python中,每个对象都有一个包含其属性的关联字典:__dict__。这个字典是可变的。执行作业时:

instance.attribute = value

实际发生的是您要分配到对象的__dict__

instance.__dict__['attribute'] = value

事实上:

>>> class A(object):
...     def __init__(self):
...             self.something = 1
... 
>>> a = A()
>>> a.__dict__
{'something': 1}
>>> a.other = 2
>>> a.__dict__
{'other': 2, 'something': 1}
>>> a.__dict__['other2'] = 3
>>> a.other2
3
在这方面,

__init__ 特别。这只是一个约定,所有属性都在那里定义,但是当你将self.attribute = value放在__init__内时,你正在完全与上面相同的东西代码:创建属性。 在大多数情况下进行初始化只是正确的方法。

(通常)声明其实例的一组预定义属性。一些元编程可以添加这种声明(例如,使用类装饰器/元类)。

如果您想提前定义班级的属性,可以使用__slots__

>>> class A(object):
...     __slots__ = ('something',)
... 
>>> a = A()
>>> a.something = 1
>>> a.other = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'other'

当您在类中定义__slots__时,其实例具有关联的__dict__,因此无法在运行时添加属性

>>> a.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__dict__'

或者,您可以重新定义__setattr__方法,以便更好地控制设置属性时发生的情况。