humanityANDpeace
humanityANDpeace

Reputation: 4637

Do most built-in Python classes lack __dict__? What are the reasons?

Is it a general rule that native Python classes, e.g. os.stat_result, have no __dict__ attribute (as for instance suggested in how to avoid class having a __dict__)?

What are the technical reasons why built-in classes (e.g. os.stat_result) lack this feature?

Upvotes: 1

Views: 595

Answers (1)

jsbueno
jsbueno

Reputation: 110311

I don't know if there is a "correct" answer for this - the reasoning is that for most of these objects one can happily live without attaching extra-attributes to their instances - and the cost of having a __dict__ is simply not worth it.

Can you try imagining if Python's ints had __dict__s? For every number, beside the 80-something bytes it takes, another 200-ish byte object would be built, so that one could have attributes to pegged to their "42"?

Also, for imutable classes, like tuples, strings, and such, the same instance can be reused in different contexts - a __dict__ in one instance could make a seemingly non-connected instance of the same object to suddenly spawn attributes.

Also, the specific class you mention os.stat_result is a named-tuple - it is meant to be immutable and compact.

So, besides the size and resource cost of creating __dict__ for most objects, there is also the coding issue: these are usually natively coded (i.e. written in C) - and th e __dict__ attribute would have to be explicitly created - so unlike classes coded in Python - one have to go out of his way to allow __dict__ in these classes, while for Python code, the detour is on avoiding __dict__.

And finally, when the community developing the language concludes that there would be any clear advantage in an object having a __dict__, it might be included. That happened with the Function object type itself a while ago - and functions now can have attributes attached to them by decorators, and this can be put to good use.

While if you need code attaching extra-attributes to a single class, you can do it the old-fashion way, and just inherit that class and convert your object to it. (I jut found out that os.stat_result is not a named_tuple, and can't be used as a base class - sorry for that - so, wrapping it in a simple class might be the simplest thing to do:

class MyStatResult:
    def __init__(self, stat_result):
         self.stat = stat_result

    def __repr__(self):
         return "Wrapper for" + repr(self.stat)

Now, if your goal is to extract the fields titles/values as a dict, and not adding extra attributes to it - the introspectable part of these objects is given by dir - in the case of os.stat_result the fieds that matter have a nice prefix:

stat = os.stat(path)

stat_dict = lambda path: {name: getattr(stat, field)  for field in dir(stat) if field.startswith("st_")}

In Python 3.8, thanks to PEP 572, one will be able to write that as a nice oneliner:

stat_dict = lambda path: {name: getattr(stat, field)  for field in dir(stat:=os.stat(path)) if field.startswith("st_")}

Upvotes: 4

Related Questions