Lucian
Lucian

Reputation: 95

Trying to understand __dict__ for Python Classes vs Instances

I understand that you can view things within Python as attributes as per this article. But I am curious as to why in an instance of a class, parent_instance, we do not have the same attributes stored within the ParentClass. This question said that, "The '__dict__' and '__weakref__' entries in a class's __dict__ (when present) are descriptors used for retrieving an instance's dict pointer and weakref pointer"

I know that with a dir(parent_instace) call, I can still obtain a '__weakref__', which will be None, and the method_1 and method_2. But why aren't these within __dict__ in a similar format only set to None?

What is setting or defining what is in __dict__? Why can I not access method attributes within an instance using __dict__. I understand it's not within the scope, but why is it not in the scope? Shouldn't the method attributes be within the instance since it can access them?

Reference Code:

class ParentClass:
    def __init__(self):
        self.int_1: int = 0
        self.str_1: str = ''

    def method_1(self):
        pass

    def method_2(self):
        pass


parent_instance = ParentClass()

print("Parent Class Attributes:")
for atr in ParentClass.__dict__:
    print(atr)

print("\nParent Instance Attributes:")
for atr in parent_instance.__dict__:
    print(atr)

Upvotes: 1

Views: 226

Answers (1)

Raymond Hettinger
Raymond Hettinger

Reputation: 226256

Question 1: The separation of instance data and class data

You asked a lot of questions, but I think the common theme is "why doen't the instance dictionary store everything that is accessible from an instance?"

The answer is that instances store information unique to each instance while classes store information (methods and class variables) that are shared by all instances.

This is central to the notion of what it means to be class (what all instances have in common), and it is memory efficient (one class and many instances).

Users don't normally access the class __dict__ or instance __dict__ directly. They use dir() to see all the levels collapsed to together and use either the dot operator or getattr() to do a look up in the chain of dictionaries (instance first and the MRO of class dictionaries). From the user's point of view, almost everything is in the object.

There are some implementation nuances such as __mro__ being only accessible from the class and not from the instance. Also, the garbage collection, refcount, and weak reference support aren't shown in the instance dictionary even though they are part of the object.

Question 2: Showing all attributes at the class level

A secondary question is "why don't classes list all attributes including instance attributes?"

There are two equivalent answers:

a) Since instance dictionaries are dynamically updatable and store both the key and value, there is no need to store this information at the class level.

b) Since instance attributes can be added after instantiation, the class cannot know in advance which attributes are going to be stored in instances.

This is true most of the time in Python (and other interpreted OOP languages). However, classes defined with __slots__ are an exception to this rule because they don't use instance dictionaries. Dataclasses may seem like an exception because they store code generation metadata at the class level, but after the code is generated they are just regular classes and the same principles apply.

Upvotes: 4

Related Questions