【问题标题】:lambda *args, **kwargs: Nonelambda *args,**kwargs:无
【发布时间】:2013-08-04 04:09:33
【问题描述】:

考虑:

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' )

这样做的动机是我不必输入逻辑来检查是否已分配回调,因为它默认为空白_fn,它什么都不做。

这行得通,但有什么理由我不应该这样做吗?它是pythonic吗?有更好的方法吗?是否有内置的:

lambda *args, **kwargs: None

【问题讨论】:

  • 使用lambda 定义命名函数不是Pythonic,不是。使用def
  • @Wooble lambda 并不复杂,甚至不复杂。因此,我会说它是 Pythonic。而且超级好用!

标签: python lambda default-arguments


【解决方案1】:

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

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

不过,我认为更 Pythonic 的方式是:

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

【讨论】:

  • 好的。我想如果我确实有一个合法的默认回调,我可以定义它并将其作为默认值传递。否则我会使用无聊的老 if... None:。 Blech!
  • 有时会发生 perform_task 做一些复杂的工作,你想尽可能多地考虑它。许多小步骤,例如采用 blank_fn 方式,都可以生成漂亮、易于管理的代码。通常更重要的是保持代码整洁而不是优化它。
【解决方案2】:

我认为前面的答案更好,因为它提供了一种更好的方式来完成 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]: 

【讨论】:

  • 在测试套件之外的任何地方使用 mock 似乎是非常糟糕的做法。与仅声明一个空函数相比,这有什么优势?这可能也慢得多
猜你喜欢
  • 2019-06-04
  • 2020-09-16
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 2018-02-15
  • 2021-07-26
  • 2022-09-22
相关资源
最近更新 更多