views:

481

answers:

2

With python properties, I can make it such that

x.y

calls a function rather than just returning a value.

Is there a way to do this with modules?

I have a case where I want m.y to call a function rather than just returning the value stored there.

C

+11  A: 

Only instances of new-style classes can have properties. You can make Python believe such an instance is a module by stashing it in sys.modules[thename] = theinstance. So, for example, your m.py module file could be:

import sys
class _M(object):
  def __init__(self):
    self.c = 0
  def afunction(self):
    self.c += 1
    return self.c
  y = property(afunction)
sys.modules[__name__] = _M()

Edited: removed an implicit dependency on globals (had nothing to do with the point of the example but did confuse things by making the original code fail!).

Alex Martelli
I would never have thought of doing that. I admit I'm unlikely to use it, but you never know. Always happy to learn about unexplored avenues in Python... thanks.
Jarret Hardie
Did anybody else try this? When I put this code in one file x.py and import it from another, then calling x.y results in AttributeError: 'NoneType' object has no attribute 'c', since _M somehow has value None...
Stephan202
You must be mistyping something. Check an interactive session:$ python...>>> import sys>>> class _M(object):... c = 0... def afunction(self):... _M.c += 1... return _M.c... y = property(afunction)...>>> sys.modules['bowwow'] = _M()>>> import bowwow>>> bowwow.y1>>> bowwow.y2>>>...exactly as expected, of course. So, what's different in what you exactly are doing?
Alex Martelli
Indeed the code works on the interpreter. But when I put it in a file (say, bowwow.py) and I import it from another file (otherfile.py), then it no longer works...
Stephan202
You're right -- I had coded it sloppily causing an unwonted dependence on globals (the code accessed _M, implicitly, from globals); now fixed, and thanks for pointing this out.
Alex Martelli
Nice, this works! Changed it form -1 to +1.
Stephan202
+5  A: 

I would do this in order to properly inherit all the attributes of a module, and be correctly identified by isinstance()

import types

class MyModule(types.ModuleType):
    @property
    def y(self):
        return 5


>>> a=MyModule("test")
>>> a
<module 'test' (built-in)>
>>> a.y
5

And then you can insert this into sys.modules

Unknown