Overriding "__setattr__" of a module - possible?

John Nagle nagle at animats.com
Wed Jun 16 14:55:43 EDT 2010


On 6/15/2010 8:34 PM, Michele Simionato wrote:
> On Jun 16, 4:43 am, John Nagle<na... at animats.com>  wrote:
>>     Is it possible to override "__setattr__" of a module?  I
>> want to capture changes to global variables for debug purposes.
>>
>>     None of the following seem to have any effect.
>>
>>          modu.__setattr__ = myfn
>>
>>          setattr(modu, "__setattr__", myfn)
>>
>>          delattr(modu, "__setattr__")
>>
>>                                  John Nagle
>
> There is a dirty trick which involves fiddling with sys.modules...

That doesn't do quite what you'd expect.  Here's a version with
more debug output:

import sys

class FakeModule(object):
    def __init__(self, dic):
        vars(self).update(dic)
    def __setattr__(self, name, value):
        print "setting %s=%s" % (name, value)
        object.__setattr__(self, name, value)

a = 1
def f():
    print ('called f, a = %s' % (a,))

print("Patching " + __name__)
sys.modules[__name__] = FakeModule(globals())

---

C:\projects\newthreading>\python26\python
ActivePython 2.6.5.12 (ActiveState Software Inc.) based on
Python 2.6.5 (r265:79063, Mar 20 2010, 14:22:52) [MSC v.1500 32 bit 
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
 >>> import x
Patching x
 >>> x.f()
called f, a = None
 >>> x.a
1
 >>> x.a = 2
setting a=2
 >>> x.f()
called f, a = None

---

Note that there are now two copies of "a", one bound to the module and
referenced in "f", and a second bound to the class, and referenced by
"x.a".  Uh oh.

The problem here is that when "def f..." was defined, its reference
to "a" was bound to the object containing "a" at the time, which is
the module-level copy of the variable.

I don't think turning a module into a class is going to work.
Binding the functions into the class won't work, because Python
doesn't have class-level (as opposed to instance-level) functions.
If we move x.f into class FakeModule, then "x.f()" is called as
"f(x)", with an unexpected argument.

Any better ideas?  All I really want to do is to override "__setattr__"
for a module.

				John Nagle



More information about the Python-list mailing list