As you already found, you can find instance attributes in an instance's __dict__
, and class attributes will not be present there (unless they were overridden for a particular instance).
If a given class uses __slots__
instead of __dict__
, then the names of instance attributes can be discovered by examining that class's __slots__
attribute. This can be further complicated in a class that extends one or more other classes that use __slots__
, including whether that subclass uses __slots__
or not itself. In such cases, you would need to inspect the __slots__
of parent classes in the MRO. Similarly, for class attributes defined in parent classes, you will need to inspect the __dict__
for each class in the MRO.
For the simpler case from your example, it is possible to have an instance attribute that overrides the class attribute for that particular instance. If the instance attribute is deleted, and that attribute is accessed again, then we will see the class attribute's value. Deletion must occur on the class attribute directly.
>>> class A:
... two = 2
... def __init__(self):
... self.one = 1
...
>>> a = A()
>>> a.one, a.two
(1, 2)
>>> a.two = 3
>>> a.one, a.two
(1, 3)
>>> A.two
2
>>> del a.two
>>> a.one, a.two
(1, 2)
>>> del A.two
>>> a.one, a.two
Traceback (most recent call last):
Cell In [47], line 1
a.one, a.two
AttributeError: 'A' object has no attribute 'two'
>>> A.two
Traceback (most recent call last):
Cell In [52], line 1
A.two
AttributeError: type object 'A' has no attribute 'two'
You may be able to learn more from some of the answers to this question:
What is the difference between class and instance attributes?