Python 中 Ruby 的 tap 习惯用法
有一个有用的 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
不是有效的语法。
There is a useful Ruby idiom that uses tap
which allows you to create an object, do some operations on it and return it (I use a list here only as an example, my real code is more involved):
def foo
[].tap do |a|
b = 1 + 2
# ... and some more processing, maybe some logging, etc.
a << b
end
end
>> foo
=> [1]
With Rails there's a similar method called returning
, so you can write:
def foo
returning([]) do |a|
b = 1 + 2
# ... and some more processing, maybe some logging, etc.
a << b
end
end
which speaks for itself. No matter how much processing you do on the object, it's still clear that it's the return value of the function.
In Python I have to write:
def foo():
a = []
b = 1 + 2
# ... and some more processing, maybe some logging, etc.
a.append(b)
return a
and I wonder if there is a way to port this Ruby idiom into Python. My first thought was to use with
statement, but return with
is not valid syntax.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果你想要这个足够糟糕,你可以创建一个上下文管理器
,你可以使用它,如下所示:
没有办法绕过
return
语句,并且with
在这里实际上不做任何事情。但你确实在开始时就有了Tap
,它可以让你了解我认为该函数的含义。它比使用 lambda 更好,因为您不限于表达式,并且可以在with
语句中拥有几乎任何您想要的内容。总的来说,我想说,如果你想要点击那么糟糕,那么就坚持使用 ruby,如果你需要用 python 编程,请使用 python 来编写 python 而不是 ruby。当我开始学习 Ruby 时,我打算编写 Ruby ;)
If you want this bad enough, you can create a context manager
which you can use like:
There's no getting around the
return
statement andwith
really doesn't do anything here. But you do haveTap
right at the start which clues you into what the function is about I suppose. It is better than using lambdas because you aren't limited to expressions and can have pretty much whatever you want in thewith
statement.Overall, I would say that if you want
tap
that bad, then stick with ruby and if you need to program in python, use python to write python and not ruby. When I get around to learning ruby, I intend to write ruby ;)我有一个想法使用函数装饰器来实现这一点,但由于Python中表达式和语句之间的区别,这最终仍然需要返回在最后。
根据我的经验,ruby 语法很少使用,而且其可读性远不如显式的 python 方法。如果 python 具有隐式返回或将多个语句包装成单个表达式的方法,那么这将是可行的 - 但它在设计上没有这些东西。
这是我的 - 有点毫无意义 - 装饰器方法,供参考:
I had an idea to achieve this using function decorators, but due to the distinction in python between expressions and statements, this ended up still requiring the return to be at the end.
The ruby syntax is rarely used in my experience, and is far less readable than the explicit python approach. If python had implicit returns or a way to wrap multiple statements up into a single expression then this would be doable - but it has neither of those things by design.
Here's my - somewhat pointless - decorator approach, for reference:
我部分同意其他人的观点,因为用 Python 实现这个没有多大意义。然而,恕我直言,Mark Byers 的方式就是方式,但为什么使用 lambda(以及它们附带的所有内容)?不能写一个单独的函数在需要的时候调用吗?
另一种方法可以实现基本相同的功能
,但据我所知,这个漂亮功能并不是 Python 3 中内置的。
I partly agree with others in that it doesn't make much sense to implement this in Python. However, IMHO, Mark Byers's way is the way, but why lambdas(and all that comes with them)? can't you write a separate function to be called when needed?
Another way to do basically the same could be
but this beautiful feature is not a built-in in Python 3, I hear.
几乎没有 Ruby 程序员以这种方式使用
tap
。事实上,我认识的所有顶级 Ruby 程序员都说,tap 除了调试之外没有任何用处。为什么不在你的代码中这样做呢?
请记住 Array 支持流畅的接口,因此您甚至可以这样做:
Hardly any Ruby programmers use
tap
in this way. In fact, all top Ruby programmers i know saytap
has no use except in debugging.Why not just do this in your code?
and remember
Array
supports a fluent interface, so you can even do this:简短的回答:Ruby 鼓励方法链接,而 Python 则不然。
我想正确的问题是:Ruby 的
tap
有什么用处?现在我对 Ruby 了解不多,但通过谷歌搜索,我得到的印象是
tap
在概念上作为方法链接很有用。在 Ruby 中,样式:
SomeObject.doThis().doThat().andAnotherThing()
非常惯用。例如,它是流畅界面概念的基础。 Ruby 的tap
是这种情况的一个特例,它不是使用SomeObject.doThis()
,而是动态定义doThis
。我为什么要解释这一切?因为它告诉我们为什么
tap
在Python中没有得到很好的支持。需要注意的是,Python 不执行调用链。例如,Python 列表方法通常返回
None
而不是返回变异列表。像map
和filter
这样的函数不是列表方法。另一方面,许多 Ruby 数组方法确实返回修改后的数组。除了某些 ORM 等某些情况之外,Python 代码不使用流畅的接口。
归根结底,这是惯用的 Ruby 和惯用的 Python 之间的区别。如果您要从一种语言转向另一种语言,则需要进行调整。
Short answer: Ruby encourages method chaining, Python doesn't.
I guess the right question is: What is Ruby's
tap
useful for?Now I don't know a lot about Ruby, but by googling I got the impression that
tap
is conceptually useful as method chaining.In Ruby, the style:
SomeObject.doThis().doThat().andAnotherThing()
is quite idiomatic. It underlies the concept of fluent interfaces, for example. Ruby'stap
is a special case of this where instead of havingSomeObject.doThis()
you definedoThis
on the fly.Why I am explaining all this? Because it tells us why
tap
doesn't have good support in Python. With due caveats, Python doesn't do call chaining.For example, Python list methods generally return
None
rather than returning the mutated list. Functions likemap
andfilter
are not list methods. On the other hand, many Ruby array methods do return the modified array.Other than certain cases like some ORMs, Python code doesn't use fluent interfaces.
In the end it is the difference between idiomatic Ruby and idiomatic Python. If you are going from one language to the other you need to adjust.
您可以按如下方式在 Python 中实现它:
用法:
但是,它在 Python 2.x 中的用途不会像在 Ruby 中那么多,因为 Python 中的 lambda 函数非常受限制。例如,您无法内联对 print 的调用,因为它是关键字,因此您不能将其用于内联调试代码。您可以在 Python 3.x 中执行此操作,尽管它不如 Ruby 语法清晰。
You can implement it in Python as follows:
Usage:
However it won't be so much use in Python 2.x as it is in Ruby because lambda functions in Python are quite restrictive. For example you can't inline a call to print because it is a keyword, so you can't use it for inline debugging code. You can do this in Python 3.x although it isn't as clean as the Ruby syntax.