Is it possible to check obj .__ dict__ if the class has a __dict__ variable?

I am wondering if there is a way to introspectively check a Python instance to see its __dict__ , despite any obstacles the programmer may encounter, as this will help me debug issues like unintended link loops and freezing resources such as open files.

A simpler example: how can I see the keys of a dict subclass if the programmer hid keys() in his own class? To do this, manually call the dict keys() method instead of inheriting a subclass call of the method version:

 # Simple example of getting to the real info # about an instance class KeyHidingDict(dict): def keys(self): return [] # there are no keys here! khd = KeyHidingDict(a=1, b=2, c=3) khd.keys() # drat, returns [] dict.keys(khd) # aha! returns ['a', 'b', 'c'] 

Now my real question is: how can I see an __dict__ instance, no matter what the programmer could do to hide it from me? If they set the class variable __dict__ , then it seems to obscure the actual __dict__ all objects inherited from this class:

 # My actual question class DunderDictHider(object): __dict__ = {'fake': 'dict'} ddh = DunderDictHider() ddh.a = 1 ddh.b = 2 print ddh.a # prints out 1 print ddh.__dict__ # drat, prints {'fake': 'dict'} 

This false value for __dict__ , as you can see, does not interfere with setting and setting the attribute, but misleads dir() by hiding a and b and displaying fake as an object instead of an instance variable instead.

Again, my goal is to write a tool that helps me introspect class instances to see “what really happens” when I wonder why a set of class instances takes up so much memory or keeps so many files open - and even though that the above situation is extremely far-fetched, finding a way around this will allow the tool to work all the time, and not say "works fine if the class you are looking at has ... [exception description above]".

I thought I could correctly capture __dict__ with something like:

 dict_descr = object.__dict__['__dict__'] print dict_descr(ddh, DunderDictHider) 

But it turns out that object does not have a __dict__ descriptor. Instead, the subtype_dict() C function seems to get a separate binding for each subclass of object that the programmer creates; there is no central way to name or obtain a descriptor so that it can be manually applied to objects whose class is its shadow.

Any ideas anyone? :)

+6
source share
2 answers

I'm not sure I'm happy with how simple it is:

 >>> class DunderDictHider(object): ... __dict__ = {'fake': 'dict'} ... >>> ddh = DunderDictHider() >>> ddh.a = 1 >>> ddh.b = 2 >>> >>> print ddh.a 1 >>> print ddh.__dict__ {'fake': 'dict'} 

The problem is that the class is cheating? Fix it!

 >>> class DictUnhider(object): ... pass ... >>> ddh.__class__ = DictUnhider >>> print ddh.a 1 >>> print ddh.__dict__ {'a': 1, 'b': 2} 

And here it is. This fails completely if the class defines any slots.

 >>> class DoesntHaveDict(object): ... __slots__ = ['a', 'b'] ... >>> dhd = DoesntHaveDict() >>> dhd.a = 1 >>> dhd.b = 2 >>> >>> print dhd.a 1 >>> dhd.__class__ = DictUnhider Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __class__ assignment: 'DoesntHaveDict' object layout differs from 'DictUnhider' >>> 
+1
source

This question is based on Jabur's answer in this thread: What is a metaclass in Python?

You can achieve what you are looking for with the help of metaclasses.

First you need to create a metaclass:

 def test_metaclass(name, bases, dict): print 'The Class Name is', name print 'The Class Bases are', bases print 'The dict has', len(dict), 'elems, the keys are', dict.keys() return dict 

Of course, prints are not required.

Then let me introduce your new DunderDictHider:

 class DunderDictHider(object): __metaclass__ = test_metaclass __dict__ = {'fake': 'dict'} 

Now you have access to all initialized elements: repr(DunderDictHider)

Output (with line print repr(DunderDictHider) ):

 The Class Name is DunderDictHider The Class Bases are (<type 'object'>,) The dict has 3 elems, the keys are ['__dict__', '__module__', '__metaclass__'] {'__dict__': {'fake': 'dict'}, '__module__': '__main__', '__metaclass__': <function test_metaclass at 0x1001df758>} 

Every time you can try

 if '__dict__' in repr(DunderDictHider) 

to find out if this class is trying to hide its __dict__ or not. Remember that the resulting output is a string. This can be done better, but the idea itself.

0
source

Source: https://habr.com/ru/post/897806/


All Articles