Referencing module.instance

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Dec 2 20:24:26 EST 2011


On Fri, 02 Dec 2011 09:49:25 -0800, Gnarlodious wrote:

> What I am doing is importing modules that have an identical instance
> name. So I say:
> 
> import Grid
> 
> Grid has its instance:
> 
> Grid.Grid()
> 
> and this is the same for all modules of my webapp. allowedPages is a
> list of modules to import, so they are quoted strings:
> 
> for page in self.allowedPages:
>    setattr(self, page, __import__(page))

So if allowedPages looks like this: ['Grid', 'Spam', 'Ham', 'Cheese'] you 
expect your instance to look like this:

self.Grid  # has the value Grid.Grid
self.Spam  # has the value Spam.Grid etc.
self.Ham
self.Cheese

Correct?

I'm not sure I like that design, it feels wrong, but perhaps I don't 
understand the reason for it. Moving along...

> The problem is that the attribute name needs to reference the Grid.Grid
> instance and not the Grid module. How would I do this? I can do it
> literally:
> setattr(self, 'Grid', Grid.Grid)
> 
> however doing it as a reference eludes me.

__import__(page) returns a module, so just grab that attribute from the 
module.

for page in self.allowedPages:
    setattr(self, page, __import__(page).Grid)


But note that this is an binding operation, like an assignment. If you 
rebind module.Grid, your instance self will not see the change:

Spam.Grid = 42  # some value
instance.read_pages()  # whatever you call the method
assert instance.Spam == 42
Spam.Grid = 23  # rebind the original
assert instance.Spam == 23  # THIS WILL FAIL!!!


If you need these attributes to be aliases to the module attribute, 
rather than independent bindings, you need to use computed properties 
rather than plain attributes. I leave that as an exercise, mainly because 
I suspect it will be very difficult.

Wait... no, I think it's easy! (Famous last words...) Try this untested 
code:

class MyClass(object):
    allowedPages = ('Grid', 'Spam', 'Ham', 'Cheese')
    def __init__(self):
        self.modules = {}
        for name in allowedPages:
            self.modules[name] = __import__(name)
    def __getattribute__(self, name):
        if name in self.allowedPages:
            return self.modules[name].Grid
        return super(MyClass, self).__getattribute__(name)


-- 
Steven



More information about the Python-list mailing list