Is there a way to insert hooks into a native dictionary type to see when a query arrives and what's looked up?
Veek M
vek.m1234 at gmail.com
Fri Dec 16 23:42:28 EST 2016
Steven D'Aprano wrote:
> 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.)
>
>
heh
If it walks like a duck and talks like a duck, it’s a duck, right? So if
this duck is not giving you the noise that you want, you’ve got to just
punch that duck until it returns what you expect. -Patrick Ewing on
Monkey/Duck patching in RailsConf 2007
More information about the Python-list
mailing list