f



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

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.

I wanted to check if when one does:

x.sin()

if the x.__dict__ was queried or if the Foo.__dict__ was queried.. I 
know method/attribute lookup starts with the instance but was wondering 
if I could see it in action vs defining __getattr__ __setattr__ in Foo 
which is a bit indirect.. and not what I want.
0
Veek
12/14/2016 6:11:31 AM
comp.lang.python 77058 articles. 6 followers. Post Follow

4 Replies
682 Views

Similar Articles

[PageSpeed] 42

On Wed, Dec 14, 2016 at 5:11 PM, Veek M <vek.m1234@gmail.com> 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.
>
> I wanted to check if when one does:
>
> x.sin()
>
> if the x.__dict__ was queried or if the Foo.__dict__ was queried.. I
> know method/attribute lookup starts with the instance but was wondering
> if I could see it in action vs defining __getattr__ __setattr__ in Foo
> which is a bit indirect.. and not what I want.

Normally, I would say "subclass dict and override __getitem__", but
interestingly, that doesn't seem to work. You can put a subclass of
dict in an object's __dict__, but Python won't call your functions -
at least, CPython 3.7 won't. Presumably the actual lookups and updates
are done by directly tinkering with the dict's internals, from C.

ChrisA
0
Chris
12/14/2016 6:29:47 AM
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

0
Steven
12/14/2016 9:38:44 AM
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
0
Veek
12/17/2016 4:42:28 AM
On Sat, Dec 17, 2016 at 3:42 PM, Veek M <vek.m1234@gmail.com> wrote:
> If it walks like a duck and talks like a duck, it=E2=80=99s a duck, right=
? So if
> this duck is not giving you the noise that you want, you=E2=80=99ve got t=
o just
> punch that duck until it returns what you expect. -Patrick Ewing on
> Monkey/Duck patching in RailsConf 2007

https://www.youtube.com/watch?v=3DPFn_agxmatg

ChrisA
0
Chris
12/17/2016 4:51:17 AM
Reply: