[英]Behaviour of class variable when it's not in __init__
I have the following Class named MyClass : 我有以下名为MyClass的类:
def __init__(self, config):
self.response = Response(config)
self.utility = Utility()
self.listl = {}
It has the following method : 它有以下方法:
def findSt(self, lv):
dvp = self.listl
if lv not in dvp:
raise Exception("ERROR: ....", lv)
else:
...
In my main code i use another method (getvalues) of that same class to give the correct value to self.listl ie: 在我的主代码中,我使用同一个类的另一个方法(getvalues)为self.listl提供正确的值,即:
myobject = MyClass(config)
myobject.listl = myobject.getvalues()
lr = []
for lv in lvs:
lr.append(myobject.findSt(lv))
This works, although i'm not sure it's the proper way to do this. 这是有效的,虽然我不确定这是否是正确的方法。 The reason i'm asking is because if i do the following typo in the main code :
我问的原因是因为如果我在主代码中执行以下拼写错误:
myobject.listL = myobject.getvalues()
No error is raised ! 没有错误! Of course in that case
myobject.listl
doesn't have the proper runtime values so it doesn't work, but why can I create a variable that is not in __init__
? 当然,在这种情况下,
myobject.listl
没有正确的运行myobject.listl
,因此它不起作用,但为什么我可以创建一个不在__init__
的变量?
For the same reason that you can set myobject.listl
-- you can set any attribute on any instance from anywhere*, attributes set in __init__
aren't special in any way. 出于同样的原因你可以设置
myobject.listl
- 你可以在任何地方设置任何实例的任何属性*, __init__
中设置的属性在任何方面都不是特殊的。 The only thing special about __init__
is that it's called automatically when a new instance is made. 关于
__init__
唯一特别之处在于它是在创建新实例时自动调用的。
That doesn't mean you have to make use of that, it's usually better not to set such attributes from outside the class, I'd prefer to have a method like 这并不意味着你必须使用它,通常最好不要从类外部设置这样的属性,我更喜欢有类似的方法
def setvalues(self):
self.listl = self.getvalues()
or so. 或者。 In general you need to be careful because you have a mutable attribute there, what if some outside code still holds a reference to the old self.listl?
一般来说,你需要小心,因为你有一个mutable属性,如果一些外部代码仍然拥有对旧self.listl的引用呢? Then that old list won't be changed by that code.
然后该代码不会更改旧列表。 This way it would be:
这样会是:
def setvalues(self):
self.listl[:] = self.getvalues()
Doesn't re-set the listl attribute, but merely the values inside it. 不重新设置listl属性,而只是重新设置其中的值。 But that's a whole different discussion.
但这是一个完全不同的讨论。
*: there are a few exceptions, like with classes implemented in C, or classes with __slots__
defined, but those are rare exceptions. *:有一些例外,例如在C中实现的类,或者定义了
__slots__
类,但这些是罕见的例外。
User-defined class instances can add/remove attributes at runtime: 用户定义的类实例可以在运行时添加/删除属性:
>>> class A(object): pass
...
>>> a = A()
>>> a.something = 1 #no error. Now a has a new something attibute
>>>
While built-in types usually don't allow this: 虽然内置类型通常不允许这样:
>>> a = object()
>>> a.something = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'something'
In python every object has an associated dictionary that contains its attributes: __dict__
. 在python中,每个对象都有一个包含其属性的关联字典:
__dict__
。 This dictionary is mutable . 这本词典是可变的 。 When you perform an assignment:
执行作业时:
instance.attribute = value
What actually happens is that you are assigning to the __dict__
of the object: 实际发生的是你分配给对象的
__dict__
:
instance.__dict__['attribute'] = value
and in fact: 事实上:
>>> 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__
is not special in this respect. __init__
在这方面并不特别。 It's just a convention that all attributes are defined there, but when you put self.attribute = value
inside __init__
you are doing exactly the same thing as the above code: creating a new attribute. 这只是一个约定 ,所有属性都在那里定义,但当你在
__init__
放置self.attribute = value
,你正在做与上面代码完全相同的事情:创建一个新属性。 It is only the proper method to do initialization most of the time. 在大多数情况下进行初始化只是正确的方法。
Classes do not (usually) declare a predefined set of attributes of their instances. 类(通常) 不会声明其实例的预定义属性集。 It is possible with some meta-programming to add this kind of declaration (eg using class-decorators/metaclasses for example).
一些元编程可以添加这种声明(例如,使用类装饰器/元类)。
If you want to define the attributes of a class in advance you can use __slots__
: 如果要提前定义类的属性,可以使用
__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'
When you define __slots__
in a class then its instance do not have an associated __dict__
, and hence its not possible to add attributes at runtime 在类中定义
__slots__
,它的实例没有关联的__dict__
,因此无法在运行时添加属性
>>> a.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__dict__'
Alternatively you can redefine the __setattr__
method to have finer control about what happens when you set an attribute. 或者,您可以重新定义
__setattr__
方法,以便更好地控制设置属性时发生的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.