字典值作为访问键时调用的函数,而不使用“()”

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)

    调用存储在var动作中的函数+() action() 您的函数将被执行。

【讨论】:

以上是关于字典值作为访问键时调用的函数,而不使用“()”的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Provider - 在值更改时调用函数而不调用 build()

Python 3:检查迭代器的下一个值而不进行迭代

我正在尝试根据一些规则将字典键与其值匹配,而不使用其他库

使用值范围作为键的字典对象

面向对象的程序设计

在 Pyspark df 中添加字典键作为列名和字典值作为该列的常量值