views:

45

answers:

2

I know this does not sound Pythonic, but bear with me for a second.

I am writing a module that depends on some external closed-source module. That module needs to get instantiated to be used (using module.create()).

My module attempts to figure out if my user already loaded that module (easy to do), but then needs to figure out if the module was instantiated. I understand that checking out the type() of each variable can tell me this, but I am not sure how I can get the names of variables defined by the main program. The reason for this is that when one instantiates the model, they also set a bunch of parameters that I do not want to overwrite for any reason.

My attempts so far involved using sys._getframe().f_globals and iterating through the elements, but in my testing it doesn't work. If I instantiate the module as modInst and then call the function in my module, it fails to show the modInst variable. Is there another solution to this? Sample code provided below.

import sys
if moduleName not in sys.modules:
    import moduleName
    modInst = moduleName.create()
else:
    globalVars = sys._getframe().f_globals
    for key, value in globalVars:
        if value == "Module Name Instance":
            return key
    return moduleName.create()

EDIT: Sample code included.

A: 

Suppose the external closed-sourced module is called extmod. Create my_extmod.py:

import extmod
INSTANTIATED=False
def create(*args,**kw):
    global INSTANTIATED
    INSTANTIATED=True
    return extmod.create(*args,**kw)

Then require your users to import my_extmod instead of extmod directly. To test if the create function has been called, just check the value of extmod.INSTANTIATED.

Edit: If you open up an IPython session and type import extmod, then type extmod.[TAB], then you'll see all the top-level variables in the extmod namespace. This might help you find some parameter that changes when extmod.create is called.

Barring that, and barring the possibility of training users to import my_extmod, then perhaps you could use something like the function below. find_extmod_instance searches through all modules in sys.modules.

def find_instance(cls):
    for modname in sys.modules:
        module=sys.modules[modname]
        for value in vars(module).values():
            if isinstance(value,cls):
                return value

x=find_instance(extmod.ExtmodClass) or extmod.create()
unutbu
unutbu,That is exactly the way I was thinking too, but I realized that I need a way to ensure that if my users do not follow instructions (which I believe is almost always the case), I do not erase their work. That is why I need to know if they instantiated it themselves or not. Of course, if that is not possible, I need to figure out another way to make sure they don't fool around too much.
Michalis Avraam
@Michalis: Okay, here is another thought then: You mentioned that there are a number of parameters you do not want to overwrite. Can you find out what the default values of these parameters are (or if they exist) and then compare them to their current values? If different, then you know the user must have called `create`... ?
unutbu
Yes, I could. But all those parameters are accessed through the instantiated object, which is what I am trying to find. Therefore, I still need to find if it has been instantiated and what name it uses.
Michalis Avraam
+1  A: 

Looks like your code assumes that the .create() function was called, if at all, by the immediate/direct caller of your function (which you show only partially, making it pretty hard to be sure about what's going on) and the results placed in a global variable (of the module where the caller of your function resides). It all seems pretty fragile. Doesn't that third-party module have some global variables of its own that are affected by whether the module's create has been called or not? I imagine it would -- where else is it keeping the state-changes resulting from executing the create -- and I would explore that.

To address a specific issue you raise,

I am not sure how I can get the names of variables defined by the main program

that's easy -- the main program is found, as a module, in sys.modules['__main__'], so just use vars(sys.modules['__main__']) to get the global dictionary of the main program (the variable names are the keys in that dictionary, along of course with names of functions, classes, etc -- the module, like any other module, has exactly one top-level/global namespace, not one for variables, a separate one for functions, etc).

Alex Martelli
Alex,Thank you very much. The sys.modules['__main__'] is much more elegant than sys._getframe(1).f_globals. Of course, they both assume that the main program is the one that called the create function and not one of their own modules, but I am not sure that is easy to solve (unless I traverse all of sys.modules). As for the .create() function creating any variables - that is not the case. All variables are store in the object create() creates for you, and nothing is stored externally. Which is why I am having so much trouble with this.Is there a way to find the object regardless module?
Michalis Avraam
@Michalis, generally speaking, no, there is no fully general way to find an object without any idea of where it might be stored. However, you might try http://docs.python.org/library/gc.html?highlight=gc#gc.get_objects -- it will return all lists and dicts (and some other containers) for you to inspect. For a large program, of course, that inspection can take quite a while!
Alex Martelli