I just spent too long on a bug like the following:
>>> class Odp():
def __init__(self):
self.foo = "bar"
>>> o = Odp()
>>> o.raw_foo = 3 # oops - meant o.foo
I have a class with an attribute. I was trying to set it, and wondering why it had no effect. Then, I went back to the original class definition, and saw that the attribute was named something slightly different. Thus, I was creating/setting a new attribute instead of the one meant to.
First off, isn't this exactly the type of error that statically-typed languages are supposed to prevent? In this case, what is the advantage of dynamic typing?
Secondly, is there a way I could have forbidden this when defining Odp
, and thus saved myself the trouble?
Python class attributes are variables of a class that are shared between all of its instances. They differ from instance attributes in that instance attributes are owned by one specific instance of the class only, and are not shared between instances.
But be careful, if you want to change a class attribute, you have to do it with the notation ClassName. AttributeName. Otherwise, you will create a new instance variable.
Adding attributes to a Python class is very straight forward, you just use the '. ' operator after an instance of the class with whatever arbitrary name you want the attribute to be called, followed by its value.
Class attributes are the variables defined directly in the class that are shared by all objects of the class. Instance attributes are attributes or properties attached to an instance of a class. Instance attributes are defined in the constructor. Defined directly inside a class.
You can implement a __setattr__
method for the purpose -- that's much more robust than the __slots__
which is often misused for the purpose (for example, __slots__
is automatically "lost" when the class is inherited from, while __setattr__
survives unless explicitly overridden).
def __setattr__(self, name, value):
if hasattr(self, name):
object.__setattr__(self, name, value)
else:
raise TypeError('Cannot set name %r on object of type %s' % (
name, self.__class__.__name__))
You'll have to make sure the hasattr
succeeds for the names you do want to be able to set, for example by setting the attributes at a class level or by using object.__setattr__
in your __init__
method rather than direct attribute assignment. (To forbid setting attributes on a class rather than its instances you'll have to define a custom metaclass with a similar special method).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With