字典值作为访问键时调用的函数,而不使用“()”
Posted
技术标签:
【中文标题】字典值作为访问键时调用的函数,而不使用“()”【英文标题】:Dictionary value as function to be called when key is accessed, without using "()" 【发布时间】:2018-02-16 19:23:01 【问题描述】:我有一个字典,它的值有时是字符串,有时是函数。对于作为函数的值,是否有一种方法可以在访问键时不显式键入 ()
来执行函数?
例子:
d = 1: "A", 2: "B", 3: fn_1
d[3]() # To run function
我想要:
d = 1: "A", 2: "B", 3: magic(fn_1)
d[3] # To run function
【问题讨论】:
为什么没有()
?不要在纽扣周围织毛衣……
不要这样做。 Explicit is better than implicit
。您代码中的含义是查找一个函数并调用它;所以代码应该看起来像你正在这样做。顺便说一句,混合这样的类型是个坏主意。你需要先检查你是否有一个字符串(因为你不能调用字符串),这会让你的生活变得更加艰难。
... 但仔细想想,听起来您确实有一个 design 问题,并且应该提出一个更能反映您真正想做的问题。即,您为什么首先拥有这本词典?
听起来你应该调用一些函数some_func(3)
,而不是写d[3]
,如果该值是可调用的,则该函数应该索引字典并调用该值。
【参考方案1】:
我认为标准库(很容易)无法做到这一点,但您可以使用模块 lazy_object_proxy
中的 lazy_object_proxy.Proxy
(它是第三方,因此您需要安装它):
>>> import lazy_object_proxy
>>> def fn_1():
... print('calculation')
... return 1000
...
>>> d = 1: "A", 2: "B", 3: lazy_object_proxy.Proxy(fn_1)
>>> print(d[3])
calculation
1000
【讨论】:
啊,非常有趣的解决方案。该库看起来对于耗时的计算非常有用。 +1【参考方案2】:使用callable()
检查变量是否可以调用:
d = 1: "A", 2: "B", 3: fn_1
if callable(d[3]):
d[3]()
else:
d[3]
【讨论】:
问的具体说是在函数调用时不使用()
【参考方案3】:
另一种可能的解决方案是创建一个自定义字典对象来实现此行为:
>>> class CallableDict(dict):
... def __getitem__(self, key):
... val = super().__getitem__(key)
... if callable(val):
... return val()
... return val
...
>>>
>>> d = CallableDict(1: "A", 2: "B", 3: lambda: print('run'))
>>> d[1]
'A'
>>> d[3]
run
perhaps more idiomatic solution 将使用try/except
:
def __getitem__(self, key):
val = super().__getitem__(key)
try:
return val()
except TypeError:
return val
请注意,上面的方法确实是为了完整性。我不建议使用它。 As pointed out in the comments,它将掩盖函数引发的TypeError
。您可以测试TypeError
的确切内容,但此时最好使用LBYL 样式。
【讨论】:
EAFP -try: return val(); except TypeError: return val
?
@AChampion 嗯,我可以改用 EAFP。在某些情况下,我真的认为这并不重要 :) 当我发布我的答案时,我真的没有考虑过。
EAFP 在这种情况下隐藏了在被调用函数内部发生的 TypeErrors。我不会用它。
@PekkaKlärck 是的,你的权利。我现在看得很清楚了。我想我在将它添加到我的答案时分心了,并没有考虑使用它的潜在后果。我会编辑。
在这个例子中d[3]
的返回值是None
,对吧? "run"
的打印是一个副作用。【参考方案4】:
另一个解决方案:你也可以传递一些使用@property
装饰的类方法:
class Test:
@property
def method(self):
return 'X'
d = 'a': 1, 'b': Test().method
print(d)
print(d['a'])
print(d['b'])
【讨论】:
这不是在访问密钥时调用的函数。它只是在定义时设置字典值:'a': 1, 'b': 'X'
【参考方案5】:
你可以试试这个:
用它的键和每个键的名称声明字典
没有()的函数
functions = '1': function1, '2':fction2, '3':fction3 ,...
使用get方法传递函数/值,返回None
如果密钥不存在action = functions.get(key)
action()
您的函数将被执行。
【讨论】:
以上是关于字典值作为访问键时调用的函数,而不使用“()”的主要内容,如果未能解决你的问题,请参考以下文章