这个问题很模糊,因为问题是出于正当理由滥用 Python。假设我有 python 作为程序输入:
scf() # produces F,C that are somehow available globally
ci() # uses F,C
问题是,可以scf
修改调用者的模块吗?
第二种情况:
F,C = scf() # F,C are not set globally.
所以基本上要么捕获值(x),要么全局设置它。如何做呢?
这个问题很模糊,因为问题是出于正当理由滥用 Python。假设我有 python 作为程序输入:
scf() # produces F,C that are somehow available globally
ci() # uses F,C
问题是,可以scf
修改调用者的模块吗?
第二种情况:
F,C = scf() # F,C are not set globally.
所以基本上要么捕获值(x),要么全局设置它。如何做呢?
分享这个让我很不舒服,但是在 CPython 中你可以改变堆栈帧:
import sys
def scf():
frame = sys._getframe(1) #caller's frame (probably)
frame.f_globals['F'] = 'F' #add/overwrite globals
frame.f_globals['C'] = 'C'
def ci():
print F, C
scf()
ci() # prints 'F C'
但是,为什么需要无形地改变调用者的命名空间呢?这是糟糕的设计。scf()
应该返回东西并且ci()
应该接受这些东西作为参数。如果您分享更多关于您正在做的事情,也许我们可以建议更好的方法。
因此,您试图在 Python 程序的外部执行字符串之间保持某种状态。这在 Python 中是微不足道的:只需保留一个显式的局部变量和全局变量命名空间,并在调用和 Friends 之间传递exec
它。
s1 = """
foo = 'bar'
"""
s2 = """
def myImpureFunction():
global foo
foo = 1
myImpureFunction()
"""
lvars, gvars = {}, {}
exec s1 in lvars, gvars
print gvars
exec s2 in lvars, gvars
print gvars
也许为了保持一些理智,您可以向您的用户保证在运行之间将保留一个特殊的 var:
s1 = """
stash.foo = 'bar'
"""
s2 = """
def myImpureFunction():
stash.foo = 'foo'
myImpureFunction()
"""
from types import ModuleType
lvars = {'stash': ModuleType('stash')}
exec s1 in lvars
print lvars['stash'].foo
exec s2 in lvars
print lvars['stash'].foo
我通常通过创建类似于以下的对象池来解决这个问题
>>> class Pool:
from collections import namedtuple, defaultdict, OrderedDict
namespace = defaultdict(OrderedDict)
@staticmethod
def add(ns='default', **kwargs):
Pool.namespace[ns].update(kwargs)
@staticmethod
def pop(ns='default', *args):
return [Pool.namespace[ns].pop(k) for k in args]
@staticmethod
def remove(ns):
if ns == 'default':
raise AttributeError
del Pool.namespace[ns]
@staticmethod
def get(ns='default', **kwargs):
if kwargs:
return namedtuple(ns,kwargs.keys())(Pool.namespace[ns][k] for k in kwargs)
else:
return namedtuple(ns,Pool.namespace[ns].keys())(*Pool.namespace[ns].values())
@staticmethod
def ns():
return Pool.namespace.keys()
@staticmethod
def purge():
Pool.namespace = defaultdict(OrderedDict)
>>> Pool.add('NS1',F=10,G=20)
>>> Pool.add('NS2',A=1,B=2)
>>> Pool.pop('NS1')
[]
>>> Pool.pop('NS1','F')
[10]
>>> Pool.get('NS1')
NS1(G=20)
>>> Pool.add(X=100,Y=200)
>>> Pool.ns()
['', 'NS1', 'NS2']
>>> Pool.remove('NS1')
>>> Pool.ns()
['', 'NS2']
>>> def sci():
Pool.add("sci",F=20,G=30)
>>> def ci():
ns_sci = Pool.get("sci")
print ns_sci.F, ns_sci.G
>>> sci()
>>> ci()
20 30
>>>
您现在可以跨函数或模块使用它,而不会污染全局命名空间。您还可以跨命名空间分布它,以便多个命名空间可以共存。
你可以创建一个类:
class A(object):
def scf(self):
self.F = 10
self.C = 20
def ci(self):
print self.F, self.C
更新:
或“独立”类:
class B(object):
@staticmethod
def scf():
B.F = 10
B.C = 20
@staticmethod
def ci():
print B.F, B.C
B.scf()
B.ci()