lambda *args, **kwargs: None

43

考虑:

blank_fn = lambda *args, **kwargs: None

def callback(x, y, z=''):
    print x, y, z

def perform_task(callback=blank_fn):
    print 'doing stuff'
    callback('x', 'y', z='z' )

这样做的动机是我不需要编写逻辑来检查是否已分配回调,因为它默认为blank_fn,该函数什么也不做。

这种方法可行,但我是否应该这样做?这是否符合Python语言风格?有更好的方法吗?是否有内置函数可以实现:

lambda *args, **kwargs: None

8
使用 lambda 定义具名函数并不符合 Pythonic 风格,建议使用 def - Wooble
@Wooble lambda并不复杂,甚至也不复杂。因此,我会说它是Pythonic的。而且它非常方便! - Gavin Ray
2
似乎在Python 3.8中,f = lambda *args, **kwargs: 1234是可行的。您可以使用f()f(1, 2, 3)甚至f(1, 2, foo=bar)来调用它,它总是返回1234。 - Basj
2个回答

52
根据 PEP8 的规定,你应该“始终使用 def 语句而不是将 lambda 表达式直接绑定到名称的赋值语句。” 因此,我要更改的一件事是:

始终使用def语句代替将lambda表达式直接绑定到名称的赋值语句。

def blank_fn(*args, **kwargs):
    pass

然而,我认为使用更具Python风格的方式来完成这个任务会更好:

def perform_task(callback=None):
    print 'doing stuff'
    if callback is not None:
        callback('x', 'y', z='z')

没有必要调用一个什么也不做的函数。检查真值比调用函数更便宜。

def do_nothing(*args, **kwargs): pass
def do_something(arg, callback=do_nothing):
    a = 1 + 2
    callback('z', z='z')
def do_something_else(arg, callback=None):
    a = 1 + 2
    if callback is not None:
        callback('z', z='z')

%timeit do_something(3)
1000000 loops, best of 3: 644 ns per loop

%timeit do_something_else(3)
1000000 loops, best of 3: 292 ns per loop

2
好的。我想,如果我有一个合法的默认回调函数,我可以定义它并将其作为默认值传递。否则,我将使用无聊的旧 if... None:。噫! - Scruffy
6
有时候,perform_task会执行一些复杂的任务,你希望尽可能地将其分解。采取像taking the blank_fn这样的小步骤可以使代码变得简洁易懂。通常情况下,保持代码的清晰比进行优化更为重要。 - Dawid Toton

0

我认为前面的答案更好,因为它提供了更好的方法来完成OP想要做的事情。

然而,在测试时或者你正在猴子补丁某些东西时,可能会有一些情况需要一个noop函数。

所以,回答OP的问题,你可以使用Mock:

In [1]: from mock import Mock

In [2]: blank_fn = Mock(return_value=None)

In [3]: blank_fn()

In [4]: blank_fn("foo")

In [5]: blank_fn(bar="foo")

In [6]: blank_fn("foobar", bar="foo")

In [7]: 

4
在测试套件之外使用模拟似乎是非常糟糕的做法。相比于声明一个空函数,这样做有什么优势呢?而且这种方式可能会更慢。 - Cruncher

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接