1

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?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
humanityANDpeace
  • 4,350
  • 3
  • 37
  • 63
  • 1
    Even if they had a `__dict__`, their data wouldn't be in it. Data in a dict is really slow and inconvenient to access from C. – user2357112 Apr 12 '19 at 06:52
  • @user2357112. You suggest **C** and performance reasons are for this? Do I understand the comment correclty as a partial answer that python3 being itself build from **C** would cause the lack of `__dict__` on some/many/all builtin classes' instances? – humanityANDpeace Apr 12 '19 at 06:55
  • 1
    `os.stat_result.__dict__['n_fields']` `Out[115]: 22` Seems to me it does have `__dict__` attribute? Am I missing something? – cosmic_inquiry Apr 12 '19 at 06:55
  • @cosmic_inquiry also likely is that *I* am missting something and you are correct. However the presence of __dict__ should as was indicated in other questions allow the desired behaviour of `json.dumbs()` to become a `{"attr":value, "attr2":value2....}` is that not so? – humanityANDpeace Apr 12 '19 at 06:59
  • @cosmic_inquiry. Wha is the `Out[115]: 22` reference/info? – humanityANDpeace Apr 12 '19 at 07:00
  • @cosmic_inquiry: You're looking at a different object. That's the `os.stat_result` type, not an instance of the type (as would be returned by `os.stat`). `os.stat_result` itself has a `__dict__`, as do all types (barring a weird metaclass hiding the attribute or something, in which case the underlying dict itself would still be there), but instances of the type have no `__dict__`. – user2357112 Apr 12 '19 at 07:01
  • @user2357112, updated the question to reference to another question, which kind of refers to *performance issues* seemingly being the reason (as suggested by you also?) that built-in class instances lacking `__dict__`. – humanityANDpeace Apr 12 '19 at 07:04
  • For why, see e.g. https://stackoverflow.com/a/1529099/3001761. For, perhaps more usefully to you, how you can proceed with getting the attributes anyway: https://stackoverflow.com/questions/14411028/python-printing-attributes-with-no-dict – jonrsharpe Apr 12 '19 at 07:04
  • Yeah, I understand the question now. I think that ^ answers it. Learned something new today. – cosmic_inquiry Apr 12 '19 at 07:12
  • 1
    Per jonrsharpe, possible duplicate of [Can't set attributes of object class](https://stackoverflow.com/questions/1529002/cant-set-attributes-of-object-class) (albeit phrased rather differently) – Davis Herring Apr 12 '19 at 17:08

1 Answers1

4

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_")}
jsbueno
  • 99,910
  • 10
  • 151
  • 209