【问题标题】:"".join(reversed(val)) vs val[::-1]...which is pythonic?"".join(reversed(val)) vs val[::-1] ...这是pythonic?
【发布时间】:2009-11-08 19:38:02
【问题描述】:

所以根据Python之禅 ... 显式优于隐式 ...稀疏优于密集 ... 可读性很重要...但又是 Flat 比嵌套更好...那么 pythonic 是什么?

val = "which is pythonic?"
print("".join(reversed(val)))

print(val[::-1])

我只是一个学习 Python 的 Java 程序员,所以我觉得这个 pythonic 东西很有趣,因为在 Java 世界 AFAIK 中没有类似的东西。

【问题讨论】:

  • 我吸取了教训,问了一个“哪个更 Pythonic”的问题;主观的,会因人而异,等等。
  • 他们俩到底是做什么的?
  • @jmucchiello:反转字符串。 "foo"[::-1]oof,就像你在阅读它时所做的 oof 一样。
  • 对于那些不知道第二个的人(比如我),切片允许通过添加额外的冒号和一个数字来指定一个步骤docs.python.org/library/…

标签: python


【解决方案1】:

我的妻子 Anna 给 x[::-1] 起了个绰号“火星笑脸”——当谈到判断什么是容易和自然大多数人,她绝对喜欢军事笑脸。 “往回走”——比“把它倒过来再加入”的详细说明更直接、更抽象!

另外,python -mtimeit 通常可以很好地判断什么是 Pythonic:顶级 Python 达人,多年来,当然倾向于优化他们最经常需要和使用的东西,所以一个非常显着的性能差异告诉你什么是“与语言及其顶级实践者的“颗粒”。按照这个分数,火星笑脸比详细的规格毫无疑问...:

$ python -mtimeit '"".join(reversed("hello there!"))'
100000 loops, best of 3: 4.06 usec per loop
$ python -mtimeit '"hello there!"[::-1]'
1000000 loops, best of 3: 0.392 usec per loop

数量级的性能差异不会留下太多怀疑的余地!-)

【讨论】:

  • 我不知道...我已经使用 Python 很多年了,但我仍然发现切片语法是 Python 最难认知的方面之一。 (例如,我发现生成器的理解更容易阅读。)但是确实没有争论速度增加一个数量级,所以我想这确实是最好的解决方案。
  • 哇哦,我很高兴我问了这个问题,即使是 Python 程序员也很惊讶——谢谢 Alex。
  • 您使用的是什么设置?我无法重现这两个语句之间的巨大差异。我测试了python 2.6和3.1,它们的执行时间大致相同......
  • @Adrien:我已经在 Python 2.6 和 3.1 (Ubuntu) 上尝试过。 “火星笑脸”快 8 倍。
  • @J.F.Sebastian:haa,我现在明白了,Windows 上的引号和双引号有问题。火星笑脸真的更快。
【解决方案2】:

第二个(在我看来)更 Pythonic,因为它更简单、更短、更清晰。

关于什么是Pythonic的更多信息,我推荐The Zen of Python

美丽胜于丑陋。
显式优于隐式。
简单胜于复杂。
复杂胜于复杂。
平面比嵌套好。
稀疏优于密集。
可读性很重要。
特殊情况不足以打破规则。
虽然实用胜过纯粹。
错误绝不应无声无息地过去。
除非明确静音。
面对模棱两可,拒绝猜测的诱惑。
应该有一种——最好只有一种——明显的方法 去做吧。
虽然这种方式一开始可能并不明显,除非你是荷兰人。
现在总比没有好。
虽然现在从来没有比现在更好正确
如果实现难以解释,那就是个坏主意。
如果实现很容易解释,那可能是个好主意。
命名空间是一个很棒的想法——让我们做更多的事情!

在我看来,你的第二个例子满足了这些原则:

美丽胜于丑陋。
简单胜于复杂。
稀疏优于密集。
可读性很重要。

【讨论】:

  • 有趣的是,当他提出问题时,您推荐了 Zen。
  • 哎呀 - 你是对的 - 我什至没看到 :) 我想这也是我的禅宗。
【解决方案3】:

正如你所拥有的那样,我会使用第一个选项,因为它清楚地表明你想要的结果是一个字符串。对于列表或其他可迭代/可切片,我会选择第二个。

第一种形式的另一个好处是,如果val 实际上不是一个字符串,而是一些其他可迭代的字符(例如某种生成器),它将起作用。在某些情况下,这会产生很大的不同。

【讨论】:

  • @Daniel 不是一个字符串也被认为是可切片/可迭代的吗?
  • @Daniel 第一种形式实际上对可迭代对象起作用:reversed() 对序列起作用。特别是,对象需要具有长度(即 len 方法)。你可以试试 reversed(itertools.repeat(1)),例如:它会引发 TypeError。
  • @EOL:是的,你是对的。好吧,我想这毕竟让我的观点没有意义。
【解决方案4】:

首先,如果您是初学者,请不要担心哪个更符合 Python 风格。这种气味语言的战争,无论如何你最终都会找到自己的意见。只需使用您认为对您来说更具可读性/更简单的方式,我认为您会找到光明的。

也就是说,我同意 Alex 的出色回答(因为他总是正确的),并且我会添加一条额外的评论,为什么您应该更喜欢第二种方法 - 第一种方法只有在 val 是一个字符串时才能正常工作。

【讨论】:

  • 不,第一个可以正确处理任何可迭代的字符串(其中字符串是单字符字符串的特殊情况可迭代)。另一方面,第二个将适用于任何可切片对象(字符串是一个示例,列表是另一个示例,但通用的可迭代对象不起作用)。虽然两者都适用于您确定输入是字符串的情况,但可能存在语义差异会抓住您的边缘情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 1970-01-01
  • 2011-10-26
  • 2022-11-18
  • 2015-01-31
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多