Is there a way to insert hooks into a native dictionary type to see when a query arrives and what's looked up?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Wed Dec 14 04:38:44 EST 2016


On Wednesday 14 December 2016 17:11, Veek M wrote:

> I know that with user classes one can define getattr, setattr to handle
> dictionary lookup. Is there a way to hook into the native dict() type
> and see in real time what's being queried.

Not easily, and maybe not at all.

There are two obvious ways to do this:

(1) monkey-patch the object's __dict__, and the class __dict__.

Unfortunately, Python doesn't support monkey-patching built-ins.

https://en.wikipedia.org/wiki/Monkey_patch

Or perhaps I should say, *fortunately* Python doesn't support it.

http://www.virtuouscode.com/2008/02/23/why-monkeypatching-is-destroying-ruby/

(2) Alternatively, you could make a dict subclass, and replace the class and 
instance __dict__ with your own.

Unfortunately, you cannot replace the __dict__ of a class:

py> class X:  # the class you want to hook into
...     pass
... 
py> class MyDict(dict):  # my custom dict
...     def __getitem__(self, key):
...             print(key)
...             return super().__getitem__(key)
... 
py> d = MyDict()
py> d.update(X.__dict__)
py> X.__dict__ = d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: attribute '__dict__' of 'type' objects is not writable


You can replace the instance dict, but Python won't call your __getitem__ 
method:

py> instance = X()
py> instance.__dict__ = MyDict()
py> instance.a = 999
py> instance.a
999

So the short answer is, No.

You might be able to create a completely new metaclass that supports this, but 
it would be a lot of work, and I'm not even sure that it would be successful.



> I wanted to check if when one does:
> 
> x.sin()
> 
> if the x.__dict__ was queried or if the Foo.__dict__ was queried..

The easiest way to do that is something like this:


py> class Test:
...     def sin(self):
...             return 999
... 
py> x = Test()
py> x.sin
<bound method Test.sin of <__main__.Test object at 0xb6fc3a4c>>
py> x.sin()
999
py> x.sin = "surprise!"
py> x.sin
'surprise!'



So now you know: an instance attribute will shadow the class attribute.

(Actually, that's not *completely* true. It depends on whether x.sin is a 
descriptor or not, and if so, what kind of descriptor.)


-- 
Steven
"Ever since I learned about confirmation bias, I've been seeing 
it everywhere." - Jon Ronson



More information about the Python-list mailing list