如果我导入一个类并通过子类重命名它,找到新的类名很简单:
>>> from timeit import Timer
>>> class Test(Timer):
... pass
...
>>> test = Test()
>>> test.__class__.__name__
'Test'
但是,如果我在导入它时对该类进行别名,它会保留其主机模块中的名称:
>>> from timeit import Timer as Test2
>>> test2 = Test2()
>>> test2.__class__.__name__
'Timer'
稍后,我想提供面向用户的输出,该输出知道他们在命名空间中给出了该类的名称。考虑:
def report_stats(timer):
print("Runtime statistics for %s:" % timer.__class__.__name__)
...
有没有办法获得字符串读取" Test2",没有迭代命名空间中的变量来测试完全匹配?
答案 0 :(得分:0)
对我自己的问题有一个非常可怕的答案;我不会接受这个,因为它可能非常脆弱(我只测试了一组有限的通话情况)。我大多只是为了挑战而追捕这个;我很可能会在实际使用案例中使用更耐用的东西。
这假设我们可以访问我们尝试导入为blah的类的 init 函数,以及某种持久的外部数据存储,至少对于更复杂的边缘情况:
import inspect, dis
class Idiom(object):
description = None
alias = None
def __init__(self, desc):
global data_ob
self.description = desc
if self.__class__.__name__ == 'Idiom':
#cheat like hell to figure out who called us
self.alias = data_ob.name_idiom(inspect.currentframe().f_back)
else:
self.alias = self.__class__.__name__
class DataOb(object):
code = None
locations = {}
LOAD_NAME = 101
codelen = None
def name_idiom(self, frame):
if not self.code:
self.code = frame.f_code
self.codelen = len(self.code.co_code)
self.locations = {y:x for x, y in dis.findlinestarts(self.code)}
target_line = frame.f_lineno
addr_index = self.locations[target_line]+1
name_index = self.code.co_code[addr_index]
# there's a chance we'll get called again this line,
# so we want to seek to the next LOAD_NAME instance(101)
addr_index += 1
while addr_index < self.codelen:
if self.code.co_code[addr_index] == self.LOAD_NAME:
self.locations[target_line] = addr_index
break
addr_index += 1
return self.code.co_names[name_index]
关于其工作原理的简短说明是:
从这里我们可以做类似的事情:
>>> from rabbit_hole import Idiom as timer_bob
>>> with timer_bob("down the rabbit hole"):
... waste_some_time = list(range(50000))
...
timer_bob: down the rabbit hole
runtime: 0:00:00.001909, children: 0:00:00, overhead: 0:00:00.001909