From: Stephen Hansen on
On 6/16/10 1:23 AM, Christian Heimes wrote:
>> There aren't any; modules do not follow the class object protocol. They
>> are simple types with a __dict__ (which you can't change, either, so no
>> replacing it with a dict that implements __setattr__).
>
> You are wrong, my friend. :)
>
> Modules follow the new style class and instance protocol. Modules aren't
> classes but instances of the internal module type. Since you can't
> overwrite magic methods on instances of new style classes you can't
> overwrite __setattr__ on module level, too.

Well, fine, be that way, all right and correct and shiznit. :)

--

Stephen Hansen
... Also: Ixokai
... Mail: me+list/python (AT) ixokai (DOT) io
... Blog: http://meh.ixokai.io/

From: John Nagle on
On 6/15/2010 8:34 PM, Michele Simionato wrote:
> On Jun 16, 4:43 am, John Nagle<na...(a)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
From: Ian Kelly on
On Wed, Jun 16, 2010 at 12:55 PM, John Nagle <nagle(a)animats.com> wrote:
> 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.

It seems to me that a proxy for the actual module would work better.

import sys

class ModuleProxy(object):

def __init__(self, module):
object.__setattr__(self, 'module', module)

def __getattribute__(self, name):
module = object.__getattribute__(self, 'module')
return getattr(module, name)

def __setattr__(self, name, value):
module = object.__getattribute__(self, 'module')
print "setting %s=%s" % (name, value)
setattr(module, name, value)

a = 1
def f():
print a

sys.modules[__name__] = ModuleProxy(__import__(__name__))


Cheers,
Ian
From: John Nagle on
On 6/16/2010 1:10 PM, Ian Kelly wrote:
> On Wed, Jun 16, 2010 at 12:55 PM, John Nagle<nagle(a)animats.com> wrote:
>> 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.
>
> It seems to me that a proxy for the actual module would work better.
>
> import sys
>
> class ModuleProxy(object):
>
> def __init__(self, module):
> object.__setattr__(self, 'module', module)
>
> def __getattribute__(self, name):
> module = object.__getattribute__(self, 'module')
> return getattr(module, name)
>
> def __setattr__(self, name, value):
> module = object.__getattribute__(self, 'module')
> print "setting %s=%s" % (name, value)
> setattr(module, name, value)
>
> a = 1
> def f():
> print a
>
> sys.modules[__name__] = ModuleProxy(__import__(__name__))
>
>
> Cheers,
> Ian

That just leaves things in a state where even "sys" and "import"
are undefined.

John Nagle

From: Ian Kelly on
On Wed, Jun 16, 2010 at 3:38 PM, John Nagle <nagle(a)animats.com> wrote:
> That just leaves things in a state where even "sys" and "import"
> are undefined.

Say what? It works fine for me.

>>> import proxy_mod
>>> proxy_mod.f()
1
>>> proxy_mod.a = 2
setting a=2
>>> proxy_mod.f()
2
>>> proxy_mod.sys
<module 'sys' (built-in)>

Ian