Maxipath
Maxipath

Reputation: 61

If everything is an object, why can't I add attributes to some?

If everything is object, then why won't the following code work:

x = 6
x.newAttrib = 8

So it's not an object, or some limited object?

Upvotes: 1

Views: 217

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1125058

Yes, everything is an object. However, everything being an object does not mean that everything takes arbitrary attributes.

Integers in Python are objects, and have attributes and methods (which are just callable attributes):

>>> x = 6
>>> x.real
6
>>> x.imag
0
>>> x.bit_length()
3

To support arbitrary attributes, an object needs to have a __dict__ mapping. Integers don't have such a mapping:

>>> x.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__dict__'

Other objects do, like functions, for example:

>>> def foo(): pass
...
>>> foo.__dict__
{}
>>> foo.bar = 'baz'

But a __dict__ mapping comes with a price: a larger memory footprint for such objects. Since Python uses a lot of integers, it makes sense to not give them a __dict__ mapping, to save memory. You very rarely would need to give them extra attributes anyway.

You can define your own classes that produce instances without a __dict__ attribute, by giving your class a __slots__ class variable; this defines the fixed attributes an instance supports. This lets you benefit from the same memory savings:

>>> class Demo(object):
...     __slots__ = ('foo',)
...
>>> d = Demo()
>>> d.foo = 'bar'
>>> d.bar = 'foo'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Demo' object has no attribute 'bar'

And vice-versa, if you create a subclass of int and not give your subclass a __slots__ variable, you can add arbitrary attributes to that subclass:

>>> class MyInt(int):
...     pass
...
>>> mi = MyInt(6)
>>> mi.foo = 'bar'

Upvotes: 10

Related Questions