有一个有用的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
不是有效的语法。
答案 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
而不是返回变异列表。 map
和filter
等函数不是列表方法。另一方面,许多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中的内置功能。