导入的模块

时间:2017-03-17 20:16:58

标签: python lambda nested

我正在尝试开发一个模块,它会自动将我的参数转换为python对象,并创建一个包含参数和对象的字典。如果找到@name @。

给出的参数名称,则模块的更多内容必须替换参数值

这里是代码和最后的例子。

#FILE convertor.py
import types 

is_lambda = lambda value    : isinstance(value, types.LambdaType) and value.__name__ == '<lambda>'

def builder(tree, target, item, delimiter):
    if delimiter not in item:
        return item
    result = ''
    copir = item.split(delimiter)
    for prefix,var in map(None,copir[::2],copir[1::2]):
        if prefix is not None: result += prefix
        if var is None: continue
        lmdcheck = is_lambda(tree[var])
        if lmdcheck or delimiter is '@':
            result += target+"[\""+var+"\"]"
        elif delimiter is '$':
            result +=  str(tree[var])
        else:
            return None
    return result

def resolve_name(tree, target, item):
    """
    Resolves links and string in RHS of parameters
    """
    # Resolve links First
    result = ''
    bld = builder(tree, target, item ,  '@')
    if bld is None: return None
    result = bld
    # And then Resolve strings
    bld = builder(tree, target, result, '$')
    if bld is None: return None
    result = bld
    return unicode(result)

def generate(params, target, parent=None):
    """
    @function generate generate recods in root initial directory
    @param params      - list of (name, value) records
    @param target      - string of variable name which will be generate (need for lambda(s)), 
    @param parent      - methodtree object which will be updated
    """
    if parent is None:
        try:
            exec target+"= {}"
        except BaseException as e:
            self.error("Cannot create target object self.{}: {}".format(target,e),"generate")
            return None
    else:
        try:
            exec target+"= parent"
        except BaseException as e:
            self.error("Cannot create target object self.{}=parent: {}".format(target,e),"generate")
            return None
    try:
        exec "tree = "+target
    except BaseException as e:
        error("Cannot create temporal variable tree for return target object:".format(e),"generate")


    for name, value in params:
        value = resolve_name(tree, target,value)    
        try:
            exec "{}[\'{}\']={}".format(target,name,value)
        except BaseException as e:
            error("Cannot execute operation self.{}[\'{}\']={}: {}".format(target,name,value,e),"generate")
            return None
    return tree

if __name__ == "__main__":
    params=[
        ['parameter', '3'],
        ['Varibale X','5'],
        ['Pwered X','@Varibale X@**@parameter@'],
        ['FunctionA','lambda x,p:x**p'],
        ['FunctionB', 'lambda k:@FunctionA@(k,$parameter$)']
    ]
    dic = generate(params,'dic')
    for n in dic:
        print n, dic[n], type(dic[n])
        if n == 'FunctionA':
            print "FunctionA:", dic[n](2,3)
        if n == 'FunctionB':
            print "FunctionB:", dic[n](2)

所以如果我运行python convertor.py

,一切都会完美运行
$ python convertor.py 
FunctionA <function <lambda> at 0x7ff116246848> <type 'function'>
FunctionA: 8
Varibale X 5 <type 'int'>
FunctionB <function <lambda> at 0x7ff1162468c0> <type 'function'>
FunctionB: 8
parameter 3 <type 'int'>
Pwered X 125 <type 'int'>

但是当我从convertor.py导入generate时,嵌套的lambda函数不起作用。

#File test.py
from convertor import generate
params=[
    ['FunctionA','lambda x,p:x**p'],
    ['parameter', '3'],
    ['FunctionB', 'lambda k:@FunctionA@(k,$parameter$)']
]
dic = generate(params,'dic')
for n in dic:
    print n, dic[n], type(dic[n])
    if n == 'FunctionA':
        print "FunctionA:", dic[n](2,3)
    if n == 'FunctionB':
        print "FunctionB:", dic[n](2)


FunctionA <function <lambda> at 0x7fe037994848> <type 'function'>
FunctionA: 8
FunctionB <function <lambda> at 0x7fe0379948c0> <type 'function'>
FunctionB:
Traceback (most recent call last):
  File "runner.py", line 14, in <module>
    print "FunctionB:", dic[n](2)
  File "<string>", line 1, in <lambda>
NameError: global name 'dic' is not defined

我在SO中找不到任何类似的主题,但它可能是重复的。

我可能理解为什么会这样。我只是想知道这有什么解决方案吗?

1 个答案:

答案 0 :(得分:2)

Python的全局变量不是真正的全局变量:它们基于每个模块。此外,函数会记住定义它们的模块,并在那里查找任何全局引用,而不是在它们被调用的模块中。

因此,您生成的lambdas在convertor.py的命名空间中被exec编辑,并将尝试在那里查找dic。可能的解决方案是向generate()添加一个参数,指定要用于全局名称的上下文:您的代码生成语句看起来像exec <something> in context。您通常会为此参数传递globals(),以使用调用模块的全局变量。