是否可以在Python中动态确定变量的名称?
例如,我有时会遇到以下情况:
name = foo if bar else baz
type = alpha or bravo
D = {
"name": name,
"type": type
}
如果可以通过D = makedict(name, type)
等方式减少重复,那就太好了。
有些相关的是,函数有时会知道自己的名字:
class Item(object):
def item_create(self, item):
dispatch("create", item)
def item_delete(self, item):
dispatch("delete", item)
这里可以通过传递类似__methodname__
的内容而不是分别明确重复“创建”和“删除”来减少重复。
(我假设装饰师可以用于此,但这看起来有点矫枉过正。)
答案 0 :(得分:10)
在一般情况下,您不能从值中推断出名称(可能没有名称,可能有多个名称等);当您拨打假设makedict(name)
时,name
的值是makedict
收到的内容,因此(再次,在一般情况下)它无法辨别出什么名称(如果有的话)价值来自。你可以自省你的调用者的命名空间,看看你是否足够幸运地遇到一个特殊情况,其值可以让你推断出名称(例如,你收到23
,并且在整个感兴趣的命名空间中只有一个名称碰巧的值为23
!),但这显然是一个脆弱且不确定的架构。另外,在您的第一个示例案例中,绝对保证特殊情况不 - name
中的值与foo
或{{baz
中的值完全相同1}},所以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
如果你热衷于通过内省挖出命名空间,而不是让调用者干净地指定它们,请查看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提供了许多替代方法来实现这种实现。
答案 1 :(得分:4)
通常,你不能在Python中这样做,因为Python有对象,而不是变量。
如果我有
L1 = [1,2]
L2 = L1
然后,L1
和L2
都指向同一个对象。它没有单个名称。
类似地:
def f1(): pass
f2 = f1
现在该函数没有单一名称,因此,您无法找到该函数的“名称”。
Python中的对象可以被许多名称引用 - 当对象的引用计数变为零时,Python会为它释放内存。
答案 2 :(得分:2)
你可以做你想要的功能:
>>> def blagnorf():
pass
>>> print blagnorf.__name__
blagnorf
但不幸的是,不是变量。您可以为您的python代码编写一个预处理器来为您完成,但是......
请注意,您可以使用他们在那里的宏系统在Scheme / Lisp中执行此操作。
答案 3 :(得分:2)
每当你渴望制作一个简单的方法,其内部仅根据方法的名称而有所不同时,你可能应该重新考虑你的界面。相反,你可以这样做:
class Item(object):
def item_action(self, action, item):
dispatch(action, item)
其中action可以是“create”,“delete”等。