How do I resolve a global variable in a module?

I have a script as follows

from mapper import Mapper

class A(object):
    def foo(self):
        print "world"

a = A()
a.foo()
Mapper['test']()

      

with Mapper

defined in file mapper.py

:

Mapper = {'test': a.foo}

      

where I want to define a function call referencing an object not defined in mapper.py

, but in source code. However, the above code gives an error

NameError: name 'a' is not defined

      

which makes sense because a

it is not defined in itself mapper.py

. However, is it possible to change the code so that the code has name resolution in the main code itself or with help globals

or something else?

To solve this problem, I could specify the implementation in mapper.py

as text and use eval

in the main code, but I would like to avoid using eval

.

Additional Information:

  • The complete function definition should be done in mapper.py

  • It is not known in advance what the instance is a

    , or from what it created.
+3


source to share


2 answers


Disallowing security holes, for example eval

, it is not possible to use a name a

in mapper.py

if the name is not defined somewhere in mapper.py

or imported from another module. There is no way to just allow mapper.py

automatic and silent access to a value a

from another module.

Also, if you use it just in a dict like in your example, it a.foo

will evaluate right after the dict is created. This will not wait until you actually call the function; once it evaluates a.foo

to create a dict it will fail because it doesn't know what it is a

.

You can work around this second problem by wrapping the element in a function (using lambda multiplicity):

Mapper = {'test': lambda: a.foo}

      

., but it still won't help if you can't somehow get a

to access internally mapper.py

.

One possibility is to parameterize yours with Mapper

a "mystery" object and then pass that object externally:

# mapper.py
Mapper = {'test': lambda a: a.foo}

# other module
from mapper import Mapper
Mapper['test'](a)()

      



Or, like the suggestion mgilson

, you could somehow "register" the object a

with Mapper

. This allows you to pass the object a

just once to register it, and then you don't have to pass it for every call:

# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}

# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()

      

Notice the two sets of parentheses at the end: one for evaluating the lambda and retrieving the function you want to call, and one for actually calling that function. You can do a similar deal, instead of using it Mapper['a']

as a reference, using a module-level variable:

# mapper.py
Mapper = {'test': lambda: a.foo}

# other module
import mapper
Mapper = mapper.Mapper

mapper.a = a
Mapper['test']()()

      

Note that this needs to be done import mapper

to set a modular variable in that other module.

You can simplify this procedure by using a special class for Mapper

instead of a regular dict, and have that class do some work in __getitem__

looking for a "known location" (eg, read some module variable) to use as a basis for evaluation a

. This would be a harder decision.

The bottom line is that you simply cannot (again, without using eval

or other such holes) write code in mapper.py

that uses the undefined variable a

, and then define the variable a

in another module and mapper.py

automatically know about it. There should be some line of code that "tells" mapper.py

which value a

you want to use.

+1


source


I'm not sure if I'm completely following, but I a

can "register" its method using Mapper

from anywhere that has a link to the Mapper:

#mapping.py
Mapper = {}

      



and then:

#main.py
from mapping import Mapper

#snip
a = A()
Mapper['test'] = a.foo #put your instance method into the Mapper dict.
#snip

Mapper['test']()

      

0


source







All Articles