Unable to set feature class attributes

So, I was playing with Python, answering this question , and I found this to be wrong:

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

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

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

Printing s.attr displays โ€œhi,โ€ as expected. Why is this so? What does the Python language specification indicate that you cannot assign attributes to vanilla objects?

+66
python language-design attributes
Oct 07 '09 at 1:07
source share
6 answers

To support arbitrary attribute assignment, an object requires a __dict__ : dict associated with the object, where arbitrary attributes can be stored. Otherwise, there is nowhere to add new attributes.

The object instance does not transfer __dict__ - if it did, it faces a terrible circular dependency problem (since dict , like everything else, inherits from object ;-), this would saddle every Python object using dict, which would mean overhead for many bytes per object that currently does not have or needs a dict (in fact, all objects that do not have arbitrary attributes are not needed or need a dict).

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

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

You do not want each int occupy 144 bytes instead of 16, right? -)

Now, when you create a class (inheriting from something), things change ...:

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

... now __dict__ added (plus, a bit more overhead), so the dint instance can have arbitrary attributes, but you pay for it flexibility.

So, what if you wanted an int with only one additional attribute foobar ...? This is a rare necessity, but Python offers a special mechanism for this purpose ...

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

... not quite as small as int , mind you! (or even two int s, one self and one self.foobar - the second can be reassigned), but, of course, much better than a dint .

When a class has a special __slots__ attribute (a sequence of strings), the class operator (more precisely, the default metaclass, type ) does not equip each instance of this class with __dict__ (and, therefore, the ability to have arbitrary attributes), just a finite hard set of โ€œslotsโ€ (mainly places, each of which may contain one link to an object) with the specified names.

Instead of losing flexibility, you get a lot of bytes per instance (maybe this only makes sense if you have millions of instances galvanizing around, but there are use cases for that).

+110
Oct 07 '09 at 1:47
source share

As the other responders said, object does not have __dict__ . object is the base class of all types, including int or str . Thus, everything that is provided by object will also be a burden for them. Even what is simple, as an optional __dict__ , will require an additional pointer for each value; this diverts an additional 4-8 bytes of memory for each object in the system, for a very limited utility.




Instead of instantiating a dummy class, in Python 3.3+ you can (and should) use types.SimpleNamespace to do this.

+16
Apr 09 '14 at 15:09
source share

This is simply due to optimization.

Dictations are relatively large.

 >>> import sys >>> sys.getsizeof((lambda:1).__dict__) 140 

Most (possibly all) classes defined in C do not have a pointer for optimization.

If you look at the source code , you will see that there are many checks to see if the object has a dict or not.

+5
Oct 07 '09 at 2:45
source share

This is because an object is a "type" and not a class. In general, all classes that are defined in C-extensions (for example, all built-in data types and so on, for example numpy arrays) do not allow adding arbitrary attributes.

+1
07 Oct '09 at 1:16
source share

So, exploring my own question, I discovered this in Python: you can inherit from things like int, and you see the same behavior:

 >>> class MyInt(int): pass >>> x = MyInt() >>> print x 0 >>> x.hello = 4 >>> print x.hello 4 >>> x = x + 1 >>> print x 1 >>> print x.hello Traceback (most recent call last): File "<interactive input>", line 1, in <module> AttributeError: 'int' object has no attribute 'hello' 

I suppose the error at the end is that the add function returns an int, so I would have to redefine functions like __add__ , etc. to save my user attributes. But all this now makes sense to me (I think) when I think of an โ€œobjectโ€ as an โ€œintโ€.

+1
Oct 07 '09 at 1:16
source share

This (IMO) is one of the fundamental limitations with Python - you cannot reopen classes. I believe that the actual problem, however, is caused by the fact that classes implemented in C cannot be changed at runtime ... Subclasses can, but not base classes.

-one
07 Oct '09 at 1:12
source share



All Articles