Ruby在Python中的轻拍成语

时间:2010-09-16 09:08:34

标签: python ruby idioms

有一个有用的Ruby成语使用tap,它允许你创建一个对象,对它做一些操作并返回它(我在这里只使用一个列表作为例子,我真正的代码更复杂) :

def foo
  [].tap do |a|
    b = 1 + 2
    # ... and some more processing, maybe some logging, etc.
    a << b
  end
end

>> foo
=> [1]

使用Rails时,有一个名为returning的类似方法,所以你可以写:

def foo
  returning([]) do |a|
    b = 1 + 2
    # ... and some more processing, maybe some logging, etc.
    a << b
  end
end

说明了一切。无论你对对象做了多少处理,它仍然清楚它是函数的返回值。

在Python中我必须写:

def foo():
  a = []
  b = 1 + 2
  # ... and some more processing, maybe some logging, etc.
  a.append(b)
  return a

我想知道是否有办法将这个Ruby习惯用法移植到Python中。我的第一个想法是使用with语句,但return with不是有效的语法。

6 个答案:

答案 0 :(得分:22)

简短回答: Ruby鼓励方法链,Python不鼓励。

我想正确的问题是:Ruby的tap对什么有用?

现在我对Ruby知之甚少,但通过谷歌搜索,我得到的印象是tap在概念上可用作方法链。

在Ruby中,样式:SomeObject.doThis().doThat().andAnotherThing()非常惯用。例如,它是fluent interfaces概念的基础。 Ruby的tap是一个特殊情况,而不是SomeObject.doThis()你动态定义doThis

为什么我要解释这一切?因为它告诉我们为什么tap在Python中没有很好的支持。有了适当的警告, Python不会进行调用链接

例如,Python列表方法通常返回None而不是返回变异列表。 mapfilter等函数不是列表方法。另一方面,许多Ruby数组方法确实返回修改后的数组。

除了某些ORM之外的某些情况,Python代码不使用流畅的接口。

最后,它是惯用的Ruby和惯用的Python之间的区别。如果您要从一种语言转到另一种语言,则需要进行调整。

答案 1 :(得分:6)

您可以在Python中实现它,如下所示:

def tap(x, f):
    f(x)
    return x

用法:

>>> tap([], lambda x: x.append(1))
[1]

然而,它在Python 2.x中的使用并不像在Ruby中那么多,因为Python中的lambda函数是相当严格的。例如,您无法内联调用print,因为它是一个关键字,因此您无法将其用于内联调试代码。您可以在Python 3.x中执行此操作,尽管它不像Ruby语法那样干净。

>>> tap(2, lambda x: print(x)) + 3
2
5

答案 2 :(得分:6)

如果你想要这么糟糕,你可以创建一个上下文管理器

class Tap(object):
    def __enter__(self, obj):
        return obj

    def __exit__(*args):
        pass
你可以使用

def foo():
    with Tap([]) as a:
        a.append(1)
        return a

return语句无法解决,with在这里没有做任何事情。但是你在开始的时候确实有Tap,这可以让你了解我的功能是什么。它比使用lambdas更好,因为你不仅限于表达式,而且可以在with语句中拥有你想要的任何内容。

总的来说,如果你想要tap那么糟糕,那么请坚持使用ruby,如果你需要在python中编程,请使用python来编写python而不是ruby。当我开始学习ruby时,我打算写ruby;)

答案 3 :(得分:1)

几乎没有任何Ruby程序员以这种方式使用tap。事实上,我所知道的所有顶级Ruby程序员除了调试外都没有用{。}}。

为什么不在代码中执行此操作?

tap

并且记住[].push(1) 支持流畅的界面,所以你甚至可以这样做:

Array

答案 4 :(得分:1)

我有一个想法是使用函数装饰器实现这一点,但由于表达式和语句之间的python区别,最终仍然要求返回到最后。

ruby​​语法在我的经验中很少使用,并且远不如显式python方法可读。如果python有隐式返回或将多个语句包装到单个表达式中的方法,那么这将是可行的 - 但它没有设计的那些东西。

这是我的 - 有点无意义 - 装饰方法,供参考:

class Tapper(object):
    def __init__(self, initial):
        self.initial = initial
    def __call__(self, func):
        func(self.initial)
        return self.initial

def tap(initial):
    return Tapper(initial)

if __name__ == "__main__":
    def tapping_example():
        @tap([])
        def tapping(t):
            t.append(1)
            t.append(2)
        return tapping

    print repr(tapping_example())

答案 5 :(得分:-1)

我部分同意其他人认为在Python中实现它没有多大意义。然而,恕我直言,Mark Byers的方式是这样的,但为什么lambdas(以及随之而来的所有)?难道你不能写一个单独的函数来在需要时调用吗?

基本相同的另一种方法可能是

map(afunction(), avariable)

但是我知道这个漂亮的功能不是Python 3中的内置功能。