Callable modules?
Bengt Richter
bokr at oz.net
Wed Jul 24 19:44:20 EDT 2002
On Tue, 23 Jul 2002 10:47:10 +0200, holger krekel <pyth at devel.trillke.net> wrote:
>Paul Rubin wrote:
>> martin at v.loewis.de (Martin v. Loewis) writes:
>> > You can put a callable object in sys.modules. Module objects
>> > themselves are not callable.
>>
>> Is this documented somewhere? I don't see it in the obvious places.
>>
>> > > If there's not a way to do this already, maybe it's a reasonable
>> > > addition.
>> >
>> > Maybe not. Why do you need this?
>>
>> Just to not have to say "foo.foo()" or "from foo import foo".
>>
>> If the main purpose of the module is to provide one function, I think
>> it's cleaner to be able to import the module and call the function
>> without special tricks.
Or just use your own trick, e.g., given
----< PR.py >------
#PR.py for Paul Rubin
def PR(): return 'Hi Paul'
-------------------
Define one-line trick:
>>> def PRimport(name, locs=locals()): locs[name] = getattr(__import__(name),name)
...
And use it thus
>>> PRimport('PR')
>>> PR
<function PR at 0x007D8FD0>
>>> PR()
'Hi Paul'
>
>Moreover, I often thought about integrating class and module types.
>I am not primarly concerned about making modules callable, although
>i might appreciate it.
>
>My use case is
>
> from somemodule.someclass import filter1
>
>where 'filter1' would reference an unbound class-method.
>I need this for implementing a class which offers filter
>functions which can be applied either as
>
> obj.filter1(args)
>or
> filter1(obj, args)
>
>Of course, you can express the latter via
>
> someclass.filter1(obj, args)
>
>but i want to have filter1 (and 41 other filter methods)
>potentially directly in the namespace. I *know* that i can write
>
> filter1=someclass.filter1
> filter2=someclass.filter2
> ...
>
>but it's redundant and you have to repeat this scheme whereever
>you use 'somemodule'. That's ugly where in fact i just want to say
>
> from somemodule.filters import filter1,filter2, filter37
>
>and someclass could inherit from 'filters', thus providing both
>invocation methods. I know that i can *hack* this to work by
>
> - doing new.module('somemodule.filters') in somemodule
> and adding the modules functions at runtime to someclass.
>
> - making up a package (with filters beeing in a different file)
> and adding the modules functions at runtime to someclass
>
> - some variant of this schema
>
>but actually, doing the above 'from ....someclass import filter1,...'
>seems much more expressive and doesn't involve any run-time hacks.
>
>I hope i made my point clear enough. Basically i'd like to
>generalize the namespace-injection methods 'import' and 'from'.
>This might involves extending the Module-type to work
>more like a "usual" class with __getattr__ and such. Probabally
>it only involves extending the import machinery.
>
>Unfortunately, i haven't found time to investigate the matter
>but maybe someone can point out that it's the path to
>all evil (read: wrong concept), anyway :-)
>
Is this what you want to do (just for grins I allowed a simple pattern
to specify filter names). I
(Warning: Not tested beyond what you see below ;-)
you can do this, given the files noted below
(ForHolger is a class in forHolger.py):
>>> from importForHolger import importForHolger as impH
>>> dir()
['__builtins__', '__doc__', '__name__', 'impH']
>>> impH('forHolger.ForHolger',globals(), locals(),['*Holg*'])
>>> dir()
['ForHolger', '__builtins__', '__doc__', '__name__', 'filterHolger1', 'filterHolger2', 'im
pH', 'methodForHolger']
>>> fh=ForHolger()
>>> fh.filterHolger1()
'filtered by Holger1: KREKEL'
>>> fh.filterHolger2()
'filtered by Holger2: krekel'
>>> filterHolger1(fh)
'filtered by Holger1: KREKEL'
>>> filterHolger2(fh)
'filtered by Holger2: krekel'
>>> methodForHolger(fh,'an arg','another')
methodForHolger called with:
self=<forHolger.ForHolger instance at 0x007D0FE0>
args=('an arg', 'another')
>>> fh.methodForHolger('an arg','another')
methodForHolger called with:
self=<forHolger.ForHolger instance at 0x007D0FE0>
args=('an arg', 'another')
>>> fh.filter1()
'KREKEL'
>>> fh.filter2()
'krekel'
>>> fh.someOtherMethod()
'OM: Krekel'
>>> impH('math',globals(), locals(),['pi','c*','*n'])
>>> for k,v in locals().items(): print '%15s = %s' % (k,`v`)
...
asin = <built-in function asin>
cos = <built-in function cos>
filterHolger1 = <function filterHolger1 at 0x007D02E0>
filterHolger2 = <function filterHolger2 at 0x007D02A0>
__builtins__ = <module '__builtin__' (built-in)>
ForHolger = <class forHolger.ForHolger at 0x007D0150>
ceil = <built-in function ceil>
atan = <built-in function atan>
cosh = <built-in function cosh>
methodForHolger = <function methodForHolger at 0x007D03A0>
tan = <built-in function tan>
fh = <forHolger.ForHolger instance at 0x007D0FE0>
__name__ = '__main__'
impH = <function importForHolger at 0x007CE1C0>
pi = 3.1415926535897931
sin = <built-in function sin>
__doc__ = None
math = <module 'math' (built-in)>
--< forHolger.py >-------------
#forHolger.py
class ForHolger:
def __init__(self, v='Krekel'): self.v = v
def methodForHolger(self, *args):
print 'methodForHolger called with:\nself=%s\nargs=%s'%(`self`,`args`)
def filter1(self): return self.v.upper()
def filter2(self): return self.v.lower()
def filterHolger1(self): return 'filtered by Holger1: %s' % self.filter1()
def filterHolger2(self): return 'filtered by Holger2: %s' % self.filter2()
def someOtherMethod(self): return 'OM: %s' % self.v
-------------------------------
--< importForHolger.py >-------
# importForHolger.py
def importForHolger(name, globs, locs, thinglist=None):
"""Walks dotted name and "imports" attributes matching thinglist patterns"""
names = name.split('.')
entity = __import__(names[0], globs, locs)
for ename in names[1:]:
entity = getattr(entity, ename) # walk to last entity
locs[names[-1]] = entity # assume we want the entity as well as selected things
for thingpatt in thinglist:
# grab things in entity matching thingslist
# allow for thingpatt or *thingpatt or thing*patt or thingpatt* or *thingpatt*
tp = thingpatt.split('*')
if len(tp)==1:
matchtest = lambda x: x==tp[0]
elif len(tp)==3: # *thingpatt*
matchtest = lambda x: x.find(tp[1])!=-1
elif tp[0]:
if tp[1]:
matchtest = lambda x: x.startswith(tp[0]) and x.endswith(tp[1])
else:
matchtest = lambda x: x.startswith(tp[0])
else:
matchtest = lambda x: x.endswith(tp[1])
for k,v in entity.__dict__.items():
if matchtest(k): locs[k]=v
-------------------------------
It seems to work inside a function too ( 2.2 on windows):
>>> def foo():
... from importForHolger import importForHolger as impH
... impH('math',globals(), locals(),['pi','c*','*n'])
... return locals()
...
>>> d=foo()
>>> for k,v in d.items(): print '%15s = %s' % (k,`v`)
...
asin = <built-in function asin>
cos = <built-in function cos>
atan = <built-in function atan>
sin = <built-in function sin>
impH = <function importForHolger at 0x007D82C0>
pi = 3.1415926535897931
cosh = <built-in function cosh>
tan = <built-in function tan>
math = <module 'math' (built-in)>
ceil = <built-in function ceil>
That doesn't do what I wanted to do, though. I wanted to make a module with
an attribute the works like a real property. So while we're on the subject (? ;-)
of "integrating class and module types" ...
given
----< testmod.py >-----------
#testmod.py
import time
def get_p(self): return self._p
def set_p(self, v): self._p=v
p = property(get_p,set_p)
_p = 'class variable default for p property'
asctime = time.asctime
def get_now(self): return self.asctime()
now = property(get_now)
-----------------------------
and
----< myImport.py >----------
# myImport.py
def myImport(name, globs=globals(), locs=locals(), *args, **kw):
import sys
class MyModule(object):
execfile(name+'.py')
tmp = MyModule()
tmp.__dict__.update(kw)
if args: tmp.import_args = args
tmp.__name__ = name
sys.modules[name] = tmp
locs[name] = tmp
return tmp
-----------------------------
this seems possible:
>>> execfile('myImport.py') # so locs get bound to interactive locs
>>> myImport('testmod')
<__main__.MyModule object at 0x007D00D0>
>>> testmod.now
'Wed Jul 24 16:50:12 2002'
>>> testmod.p
'class variable default for p property'
>>> testmod.p='instance value'
>>> testmod.p
'instance value'
>>> del testmod._p
>>> testmod.p
'class variable default for p property'
Only tested as far as you see above ;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list