17

In python, it is illegal to create new attribute for an object instance like this

>>> a = object()
>>> a.hhh = 1

throws

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

However, for a function object, it is OK.

>>> def f():
...   return 1
...
>>> f.hhh = 1

What is the rationale behind this difference?

5
  • +1, I was just about to ask the exact same question but then remembered to search for an existing one first! Good answers below, too. Commented Mar 31, 2010 at 22:53
  • very good question, i am having a similar problem Commented Nov 26, 2013 at 20:27
  • possible duplicate of Can't set attributes of object class Commented Dec 17, 2013 at 16:03
  • @MartijnPieters my question is raised on 2 Jul 09. The duplicate you cited is raised on 7 Oct 09. Why would you raise a duplicate flag on this question? Commented Dec 17, 2013 at 23:20
  • @AnthonyKong: Because we (python chat room) are trying to consolidate the duplicates and into one with a clear problem description and canonical answer. Note that it doesn't matter that much which question was earlier for dupe votes, more which one can work better as a canonical dupe target. Commented Dec 17, 2013 at 23:24

4 Answers 4

22

The reason function objects support arbitrary attributes is that, before we added that feature, several frameworks (e.g. parser generator ones) were abusing function docstrings (and other attribute of function objects) to stash away per-function information that was crucial to them -- the need for such association of arbitrary named attributes to function objects being proven by example, supporting them directly in the language rather than punting and letting (e.g.) docstrings be abused, was pretty obvious.

To support arbitrary instance attributes a type must supply every one of its instances with a __dict__ -- that's no big deal for functions (which are never tiny objects anyway), but it might well be for other objects intended to be tiny. By making the object type as light as we could, and also supplying __slots__ to allow avoiding per-instance __dict__ in subtypes of object, we supported small, specialized "value" types to the best of our ability.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks Alex, for this inside view of object. I hope the gain in space was worth the effort. I still find it counter-intuitive that (a) the base class of the object system does not support one of the basic features of OO - instance attributes; and (b) this feature all of a sudden springs into existence with any non-sensical derived class class Foo(object): pass, which I find myself using more than often just to get instance attributes.
@Thomas, are you equally surprised that Object in Java "does not support one of the basic features of OO" in exactly the same way? Its direct instances don't have instance attributes either. C# is the same, I believe. Since (and this is REALLY a basic feature of OO's: Liskov's Principle!) no subclass can take away something that's in the superclass, to satisfy your intuition would actually cost infinite memory: a dict should then have a dict_... and THAT dict should of course have its OWN dict... and it can NEVER, NEVER stop. Your intuition's misleading you A LOT!-)
@Alex Ok, I hear you. But maybe this would all be possible if the __dict__'s of lean objects were lazy?! I actually could envision myself wanting to annotate the __dict__ of a __dict__ of an object instance with a little attribute, and it would be perfectly enough for me if this __dict__ would only spring into existence when I first assign to it. How is that?
@ThomasH: it's possible (at the cost of about 4 bytes/object as every object will need space for a dict pointer, NULL if it doesn't yet have a dict; not cheap, bloating Python's memory footprint very measurably, but better than the 64 bytes an empty dict costs) though quite tricky. I suggest experimenting with a specialized metaclass before drafting a PEP and patch for the C runtime, the metaclass will be much simpler and still reveal many of the difficulties (previously immutable objects now can change; what cascading effects will that have? etc). Good luck (you'll need some!-).
Ha, Alex, I don't think I'll be so bold as to file a PEP (I've seen some of them going down), but thanks for the insights anyway, appreciate that. Maybe I finally start reading Kickzales' et al. Art of the MetaObject Protocol...
|
7

Alex Martelli posted an awesome answer to your question. For anyone who is looking for a good way to accomplish arbitrary attributes on an empty object, do this:

class myobject(object):
    pass

o = myobject()
o.anything = 123

Or more efficient (and better documented) if you know the attributes:

class myobject(object):
    __slots__ = ('anything', 'anythingelse')

o = myobject()
o.anything = 123
o.anythingelse = 456

1 Comment

Are you sure that the first way works? I have tried that and I don't think it works.
1

The rationale is that an instance of object() is a degenerate special case. It "is" an object but it isn't designed to be useful by itself.

Think of object as a temporary hack, bridging old-style types and classes. In Python 3.0 it will fade into obscurity because it will no longer be used as part of

class Foo( object ):
    pass

f = Foo()
f.randomAttribute = 3.1415926

2 Comments

Main real use of object is in the idiom sentinel=object(). It WOULD be modestly handy to have an "objectwithadict" builtin at hand rather than having to make new classes for the purpose, soemetimes;-).
objectwithadict -- essentially class ObjectWithADict(object): pass?
0

Here's another alternative, as short as I could make it:

>>> dummy = type('', (), {})()
>>> dummy.foo = 5
>>> dummy.foo
5

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.