Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't set attributes on instance of "object" class

So, I was playing around with Python while answering this question, and I discovered that this is not valid:

o = object() o.attr = 'hello' 

due to an AttributeError: 'object' object has no attribute 'attr'. However, with any class inherited from object, it is valid:

class Sub(object):     pass  s = Sub() s.attr = 'hello' 

Printing s.attr displays 'hello' as expected. Why is this the case? What in the Python language specification specifies that you can't assign attributes to vanilla objects?

like image 316
Smashery Avatar asked Oct 07 '09 01:10

Smashery


People also ask

Can't set attribute values?

The reason you are getting this error is because you are naming the setter method incorrectly. You have named the setter method as set_x which is incorrect, this is why you are getting the Attribute Error.

How do you change the attributes of an object?

After you have created an object, you can set or change its properties by calling the property directly with the dot operator (if the object inherits from IDL_Object) or by calling the object's SetProperty method.

Can a class contain instance attributes?

Classes contain characteristics called Attributes. We make a distinction between instance attributes and class attributes. Instance Attributes are unique to each object, (an instance is another name for an object). Here, any Dog object we create will be able to store its name and age.

Why am I getting Attributeerror object has no attribute?

It's simply because there is no attribute with the name you called, for that Object. This means that you got the error when the "module" does not contain the method you are calling.


Video Answer


2 Answers

To support arbitrary attribute assignment, an object needs a __dict__: a dict associated with the object, where arbitrary attributes can be stored. Otherwise, there's nowhere to put new attributes.

An instance of object does not carry around a __dict__ -- if it did, before the horrible circular dependence problem (since dict, like most everything else, inherits from object;-), this would saddle every object in Python with a dict, which would mean an overhead of many bytes per object that currently doesn't have or need a dict (essentially, all objects that don't have arbitrarily assignable attributes don't have or need a dict).

For example, using the excellent pympler project (you can get it via svn from here), we can do some measurements...:

>>> from pympler import asizeof >>> asizeof.asizeof({}) 144 >>> asizeof.asizeof(23) 16 

You wouldn't want every int to take up 144 bytes instead of just 16, right?-)

Now, when you make a class (inheriting from whatever), things change...:

>>> class dint(int): pass ...  >>> asizeof.asizeof(dint(23)) 184 

...the __dict__ is now added (plus, a little more overhead) -- so a dint instance can have arbitrary attributes, but you pay quite a space cost for that flexibility.

So what if you wanted ints with just one extra attribute foobar...? It's a rare need, but Python does offer a special mechanism for the purpose...

>>> class fint(int): ...   __slots__ = 'foobar', ...   def __init__(self, x): self.foobar=x+100 ...  >>> asizeof.asizeof(fint(23)) 80 

...not quite as tiny as an int, mind you! (or even the two ints, one the self and one the self.foobar -- the second one can be reassigned), but surely much better than a dint.

When the class has the __slots__ special attribute (a sequence of strings), then the class statement (more precisely, the default metaclass, type) does not equip every instance of that class with a __dict__ (and therefore the ability to have arbitrary attributes), just a finite, rigid set of "slots" (basically places which can each hold one reference to some object) with the given names.

In exchange for the lost flexibility, you gain a lot of bytes per instance (probably meaningful only if you have zillions of instances gallivanting around, but, there are use cases for that).

like image 185
Alex Martelli Avatar answered Oct 12 '22 19:10

Alex Martelli


As other answerers have said, an object does not have a __dict__. object is the base class of all types, including int or str. Thus whatever is provided by object will be a burden to them as well. Even something as simple as an optional __dict__ would need an extra pointer for each value; this would waste additional 4-8 bytes of memory for each object in the system, for a very limited utility.


Instead of doing an instance of a dummy class, in Python 3.3+, you can (and should) use types.SimpleNamespace for this.