我正在尝试识别同一线路的来电者。下面是一个例子:
def get_file():
caller_id = get_caller_id()
return open(caller_id, 'a+')
def write_content():
with get_file() as f1, get_file() as f2: # line with multiple callers
f1.write('123')
f2.write('456')
def fun():
write_content()
write_content()
write_content()
write_content()
write_content()
get_caller_id()
函数就是我想要的。它将为函数 id
中的第一次和第二次 get_file()
调用生成两个不同的 write_content()
s,但是对于函数 write_content()
中的所有 5 次 fun()
调用,两次 get_file()
调用中的每一次都将在这 5 次 write_content()
调用中返回一个相同的文件对象。
调用 fun()
后,只会生成两个文件,一个内容为'123123123123123',另一个内容为'456456456456456'。返回的caller_id
只能对当前运行的session保持一致,python内核重启后caller_id
不一致也没关系。
我试过 inspect
模块:
def get_caller_id():
cur_frame = inspect.currentframe()
caller_frame = inspect.getouterframes(cur_frame)[2]
frame_obj = caller_frame[0]
line_no = caller_frame[2]
return '{}_{}'.format(id(frame_obj), line_no)
当一行中只有一个get_file()
调用时,这个get_caller_id()
效果很好。但是对于来自同一线路的多个调用者,它会生成相同的 ID,这不是我想要的。
我搜索了如何在一行中获取调用者的列位置,但一无所获。这种定位可能吗?
谢谢。
编辑:
下面是我实际做的:
class AutoSharedParams(object):
def __init__(self, dict_key='root', params_dict=None, init_value=None):
if params_dict is None:
params_dict = {}
self._params_dict = params_dict
self._dict_key = dict_key
if self._dict_key not in self._params_dict and init_value is not None:
self.x = init_value
def __call__(self, init_value=None, func=None):
caller_frame = inspect.getouterframes(inspect.currentframe())[1]
caller_id = id(caller_frame[0])
caller_ln = caller_frame[2]
key = '{}_c{}_l{}'.format(self._dict_key, caller_id, caller_ln)
if key not in self._params_dict:
if func:
init_value = func()
else:
init_value = None
return AutoSharedParams(dict_key=key, params_dict=self._params_dict, init_value=init_value)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
return False
@property
def x(self):
if self._dict_key in self._params_dict:
return self._params_dict[self._dict_key]
else:
return None
@x.setter
def x(self, value):
self._params_dict[self._dict_key] = value
我使用 lasagne
创建 CNN(asp
是 AutoSharedParams
的一个实例):
with asp(func=lambda: lasagne.init.HeNormal(gain='relu')) as w:
l = Conv2DLayer(l, num_filters=16, filter_size=(3, 3), W=w.x)
w.x = l.W
with asp(init_value=0) as w, asp(init_value=0) as b: # there are two calls in one line
l = Conv2DLayer(l, num_filters=16, filter_size=(3, 3), W=w.x, b=b.x)
w.x = l.W
b.x = l.b
我有很多与上面类似但不同的代码,当这段代码再次通过时,我想分享那些创建的参数( w.x
、 b.x
和许多其他)。最简单的方法是 list.append(w)
和 w=list.pop(0)
,但是当代码中有不同的路径时它会不兼容。所以我需要一把 key 来标记它们。
最佳答案
我想你需要这样的东西:
>>> import inspect
>>> def f():
curframe = inspect.currentframe()
curframe = inspect.getouterframes(curframe, 2)
caller = curframe[1][3]
if caller == 'f1':
print "f() called f1()"
elif caller == "f2":
print "f() called f2()"
else:
print "f() called by an unknwon!"
>>> def f1():
f()
>>> def f2():
f()
>>> def f3():
f()
工作如下:
>>> f1()
f() called f1()
>>> f2()
f() called f2()
>>> f3()
f() called by an unknwon!
>>>
修改 f()
以对不同的调用者有不同的行为。
关于python - 如何从被叫方的同一线路中识别多个调用者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36953002/