Reputation: 829
I have the following Class named 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:
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__
?
Upvotes: 0
Views: 46
Reputation: 101979
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__
. 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:
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. 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.
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 (e.g. using class-decorators/metaclasses for example).
If you want to define the attributes of a class in advance you can use __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
>>> 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.
Upvotes: 1
Reputation: 31260
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. The only thing special about __init__
is that it's called automatically when a new instance is made.
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? 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. 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.
Upvotes: 1