Python中的变量名自省 [英] variable name introspection in Python

查看:89
本文介绍了Python中的变量名自省的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to dynamically determine the name of a variable in Python?

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

For example, I sometimes have the following situation:

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

D = {
    "name": name,
    "type": type
}

如果可以使用D = makedict(name, type)之类的方法减少重复,那将是很好的选择.

It would be nice if duplication there could be reduced with something like D = makedict(name, type).

从某种意义上说,有时函数知道自己的名称可能会有所帮助:

Somewhat relatedly, it would sometimes be helpful for a function to know its own name:

class Item(object):

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

    def item_delete(self, item):
        dispatch("delete", item)

通过传递类似__methodname__之类的内容可以减少重复,而不是分别显式地重复"create"和"delete". (我认为可以使用装饰器,但这似乎有些过分.)

Here duplication might be reduced by passing something like __methodname__ instead of explicitly repeating "create" and "delete", respectively. (I assume a decorator could be used for this, but that seems like overkill.)

推荐答案

在一般情况下,您不能从值中推断出名称(可能没有名称,可能有多个名称,等等);当您调用假设的makedict(name)时,namemakedict接收到的,因此(同样,在一般情况下)它无法辨别该值来自什么名称(如果有)从.您可以内省调用方的名称空间,以查看是否有幸遇到一个特殊情况,即该值确实可以推断名称(例如,您收到23,并且在整个感兴趣的名称空间中只有一个名称会发生的值是23!),但这显然是一个脆弱且不稳定的体系结构.另外,在您的第一个示例案例中,绝对保证不会发生特殊情况-name中的值与foobaz中的值完全相同,因此100%确信该值的名称将毫无希望地变得模棱两可.

In the general case, you cannot deduce the name from a value (there might be no name, there might be multiple ones, etc); when you call your hypothetical makedict(name), the value of name is what makedict receives, so (again, in the general case) it cannot discern what name (if any) the value came from. You could introspect your caller's namespaces to see if you're lucky enough to hit a special case where the value does let you infer the name (e.g., you receive 23, and there's only one name throughout the namespaces of interest which happens to have a value of 23!), but that's clearly a fragile and iffy architecture. Plus, in your first example case, it's absolutely guaranteed that the special case will not occur -- the value in name is exactly the same as in either foo or baz, so it's 100% certain that the name for that value will be hopelessly ambiguous.

您可以采取完全不同的方法,例如调用makedict('name type', locals())(通过黑暗和深刻的自省魔法可以显式地忽略通过locals(),但这通常不是最可靠的选择)-传递名称(我建议使用名称空间!),并用makedict推导,这显然是一个更可靠的主张(因为每个名称都只有一个值,但是不是,反之亦然).即:

You could take a completely different tack, such as calling makedict('name type', locals()) (passing locals() explicitly might be obviated with dark and deep introspection magic, but that's not the most solid choice in general) -- pass in the names (and namespaces, I suggest!) and have makedict deduce the values, which is obviously a much more solid proposition (since each name has exactly one value, but not viceversa). I.e.:

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

如果您希望通过自省来挖掘名称空间,而不是由调用者明确指定它们,请查看

If you're keen on digging out the namespaces by introspection, rather than have them cleanly specified by the caller, look at inspect.getouterframes -- but I suggest you reconsider.

您提出的第二个问题是完全不同的(尽管您可以再次使用inspect函数来内省调用方的名称或函数本身的名称-这是一个奇特的想法!).这两种情况的共同点是,您正在使用功能强大且危险的机械来完成可以更简单地完成的工作(更容易确保正确性,更容易调试任何问题,更容易测试等)- -装饰器远非过分杀伤",它们比您建议的内省化更简单,更明确.如果您有不计其数的方法,请填写以下表格:

The second issue you raise is quite different (though you could use inspect functions again to introspect the caller's name, or a function's own name -- what a peculiar idea!). What's in common in the two cases is that you're using extremely powerful and dangerous machinery to do a job that could be done much more simply (easier to ensure correctness, easier to debug any problems, easier to test, etc, etc) -- far from having decorators be "overkill", they're far simpler and more explicit than the introspection you propose. If you have a zillion methods all of the form:

def item_blah(self, item):
    dispatch("blah", item)

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

the simplest way to create them might be:

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提供了许多替代方法来实现此主意.

Avoiding repetition is an excellent idea, but runtime introspection is not generally the best way to implement that idea, and Python offers many alternative ways to such implementation.

这篇关于Python中的变量名自省的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆