像内联一样调用python函数
我想在一个不同的模块里写一个函数,当这个函数被调用时,它能够访问调用它的地方所有的变量,就像它的代码直接粘贴到调用的地方一样,而不是有自己的上下文。简单来说,就像C语言里的宏,而不是普通的函数。我知道我可以把locals()传给这个函数,这样它就能把局部变量当作字典来访问,但我想要的是能够正常访问这些变量(比如用x.y,而不是x["y"]),而且我希望能够访问调用者能接触到的所有名字,而不仅仅是局部变量,还包括那些在调用者文件中“导入”的东西,但在包含这个函数的模块中没有导入。
这样做可能吗?
编辑 2 这是我能想到的最简单的例子,说明我真正想做的事情:
def getObj(expression)
ofs = expression.rfind(".")
obj = eval(expression[:ofs])
print "The part of the expression Left of the period is of type ", type(obj),
问题是,'expression'需要调用者的导入和局部变量才能正确执行而不出错。实际上,涉及的内容远不止一个eval,所以我想避免仅仅把locals()传递给eval(),因为那样无法解决我一般情况下的问题。
4 个回答
这样做可能吗?
可以(有点复杂,绕了个大圈),但我一般不推荐这样做(稍后会详细说明)。
考虑一下:
myfile.py
def func_in_caller():
print "in caller"
import otherfile
globals()["imported_func"] = otherfile.remote_func
imported_func(123, globals())
otherfile.py
def remote_func(x1, extra):
for k,v in extra.iteritems():
globals()[k] = v
print x1
func_in_caller()
这样做会得到(如预期的那样):
123
in caller
我们在这里做的是一些小把戏:我们只是把每个项目复制到另一个命名空间中,以便让它工作。这种做法很容易出问题,可能会导致难以发现的错误。
几乎肯定有更好的方法来解决你的问题或组织你的代码(我们需要更多信息来了解你想要实现的目标)。
还有一种更糟糕的方法来实现这个功能——请不要这样做,尽管它是可能的——
import sys
def insp():
l = sys._getframe(1).f_locals
expression = l["expression"]
ofs = expression.rfind(".")
expofs = expression[:ofs]
obj = eval(expofs, globals(), l)
print "The part of the expression %r Left of the period (%r) is of type %r" % (expression, expofs, type(obj)),
def foo():
derp = 5
expression = "derp.durr"
insp()
foo()
输出结果是
表达式 'derp.durr' 中,点左边的部分 ('derp') 是类型 (类型为 'int')
我知道这可能不是你想听的答案,但从调用模块的范围去访问局部变量其实不是个好主意。如果你平时用PHP或C语言编程,可能会习惯这种做法。
如果你还是想这么做,可以考虑创建一个类,然后把这个类的实例传递进去,代替locals()
:
#other_module.py
def some_func(lcls):
print(lcls.x)
然后,
>>> import other_module
>>>
>>>
>>> x = 'Hello World'
>>>
>>> class MyLocals(object):
... def __init__(self, lcls):
... self.lcls = lcls
... def __getattr__(self, name):
... return self.lcls[name]
...
>>> # Call your function with an instance of this instead.
>>> other_module.some_func(MyLocals(locals()))
'Hello World'
试试看吧。