在一般情况下,您不能从一个值中推断出名称(可能没有名称,可能有多个名称,等等);当您调用您假设的 makedict(name) 时,name 的 值 是 makedict 收到的,因此(再次,在一般情况下)它无法辨别值的名称(如果有的话)从。你可以检查你的调用者的命名空间,看看你是否有幸遇到一个特殊情况,该值确实可以让你推断名称(例如,你收到23,并且在感兴趣的命名空间中只有一个名称恰好发生在具有23!) 的值,但这显然是一个脆弱且不稳定的架构。另外,在您的第一个示例案例中,绝对保证特殊情况不会发生——name 中的值与foo 或baz 中的值完全相同,所以它是100% 确定该值的名称绝对是模棱两可的。
您可以采取完全不同的策略,例如调用makedict('name type', locals())(明确地传递locals() 可能会被黑暗和深入的内省魔法所避免,但这通常不是最可靠的选择)- 传递 names(还有命名空间,我建议!)并让makedict 推导出值,这显然是一个更可靠的命题(因为每个名称都有一个值,但 不反之亦然)。即:
def makedict(names, *namespaces):
d = {}
for n in names.split():
for ns in namespaces:
if n in ns:
d[n] = ns[n]
break
else:
d[n] = None # or, raise an exception
如果您热衷于通过自省来挖掘命名空间,而不是让调用者明确指定它们,请查看 inspect.getouterframes -- 但我建议您重新考虑。
您提出的第二个问题完全不同(尽管您可以再次使用inspect 函数来内省调用者的名称或函数自己的名称——多么奇特的想法!)。这两种情况的共同点是您使用极其强大和危险的机器来完成一项可以更简单地完成的工作(更容易确保正确性,更容易调试任何问题,更容易测试等) - - 远非让装饰器“矫枉过正”,它们远比您提出的内省更简单、更明确。如果你有无数种方法,所有的形式:
def item_blah(self, item):
dispatch("blah", item)
创建它们的最简单方法可能是:
class Item(object): pass
def _makedispcall(n):
def item_whatever(self, item):
dispatch(n, item)
item_whatever.__name__ = 'item_' + n
return item_whatever
for n in 'create delete blah but wait theres more'.split():
setattr(Item, 'item_' + n, _makedispcall(n))
避免重复是一个绝妙的想法,但运行时自省通常不是实现该想法的最佳方式,Python 提供了许多替代方式来实现这种实现。