Python中的变量名称内省

AnC*_*AnC 4 python metaprogramming

是否可以在Python中动态确定变量的名称?

例如,我有时会遇到以下情况:

name = foo if bar else baz
type = alpha or bravo

D = {
    "name": name,
    "type": type
}
Run Code Online (Sandbox Code Playgroud)

如果可以通过类似的方式减少重复,那将是很好的D = makedict(name, type).

有点相关,函数有时会知道自己的名字:

class Item(object):

    def item_create(self, item):
        dispatch("create", item)

    def item_delete(self, item):
        dispatch("delete", item)
Run Code Online (Sandbox Code Playgroud)

这里可以通过传递诸如__methodname__而不是分别明确地重复"创建"和"删除"之类的东西来减少重复.(我假设装饰师可以用于此,但这看起来有点过分.)

Ale*_*lli 10

在一般情况下,您不能从值中推断出名称(可能没有名称,可能有多个名称等); 当你打电话给你的假设makedict(name),该name就是makedict接收,因此(再次,在一般情况下),它不能识别的价值来自哪名(如果有的话).你可以自省你的调用者的命名空间,看看你是否足够幸运地遇到一个特殊情况,其中值可以让你推断出名称(例如,你收到的23,并且在感兴趣的命名空间中只有一个名称恰好有一个值的23!),但是这显然是一个脆弱的,前途未卜的架构.另外,在你的第一个例子情况下,它是绝对有保障的,将特殊情况不会发生-在价值name是完全一样的两种foobaz,所以这是100%肯定,该值的名称将是无可救药含糊.

你可以采取一种完全不同的方式,比如调用makedict('name type', locals())(locals()显式传递可能会被黑暗和深刻的内省魔法所避免,但这不是一般中最坚固的选择) - 传入名称(和命名空间,我建议!)并且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
Run Code Online (Sandbox Code Playgroud)

如果你热衷于通过内省来挖掘命名空间,而不是让调用者干净地指定它们,请查看inspect.getouterframes - 但我建议你重新考虑.

你提出的第二个问题是完全不同的(虽然你可以inspect再次使用函数来内省调用者的名字,或者函数自己的名字 - 这是一个多么奇怪的想法!).这两种情况的共同之处在于,您使用极其强大且危险的机器来完成更简单的工作(更容易确保正确性,更容易调试任何问题,更容易测试等等) - -远远没有装饰是"杀鸡用牛刀",他们远远比你提出的内省更简单,更清晰.如果您拥有所有形式的无数方法:

def item_blah(self, item):
    dispatch("blah", item)
Run Code Online (Sandbox Code Playgroud)

创建它们的最简单方法可能是:

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))
Run Code Online (Sandbox Code Playgroud)

避免重复是一个很好的想法,但运行时内省通常不是实现该想法的最佳方式,Python提供了许多这种实现的替代方法.