我非常了解Ruby。我相信我现在可能需要学习Python。对于那些了解两者的人来说,两者之间的概念是相似的,有什么不同?
我正在寻找一个类似于我为Learning Lua for JavaScripters编写的引物的列表:简单的事情,如空白意义和循环结构; Python中nil
的名称,以及哪些值被视为“真实”;使用相当于map
和each
,或者嘟嘟 somethingaboutlistcomprehensions mumble 标准是不是惯用的?< / p>
如果我得到了各种各样的答案,我很乐意将它们汇总到社区维基中。或者你们都可以互相争斗,试图创造一个真正的综合名单。
编辑:要明确,我的目标是“正确”和惯用的Python。如果有一个等价于inject
的Python,但没有人使用它,因为有更好/不同的方法来实现迭代列表和累积结果的常用功能,我想知道你是怎么做的。也许我会用一系列共同目标来更新这个问题,如何在Ruby中实现它们,并询问Python中的等价物是什么。
答案 0 :(得分:150)
以下是我的一些主要区别:
Ruby有块; Python没有。
Python有功能; Ruby没有。在Python中,您可以使用任何函数或方法并将其传递给另一个函数。在Ruby中,一切都是方法,方法不能直接传递。相反,你必须将它们包装在Proc中以传递它们。
Ruby和Python都支持闭包,但以不同的方式。在Python中,您可以在另一个函数中定义一个函数。内部函数具有对外部函数的变量的读访问权,但不具有写访问权。在Ruby中,您可以使用块定义闭包。闭包具有对外部作用域的变量的完全读写访问权。
Python有列表推导,非常具有表现力。例如,如果您有一个数字列表,则可以编写
[x*x for x in values if x > 15]
获取所有大于15的值的方块的新列表。在Ruby中,您必须编写以下内容:
values.select {|v| v > 15}.map {|v| v * v}
Ruby代码感觉不那么紧凑。它也没那么高效,因为它首先将values数组转换为包含大于15的值的较短中间数组。然后,它获取中间数组并生成包含中间体方块的最终数组。然后抛出中间阵列。因此,Ruby在计算期间最终在内存中有3个数组; Python只需要输入列表和结果列表。
Python也提供类似的地图理解。
Python支持元组; Ruby没有。在Ruby中,您必须使用数组来模拟元组。
Ruby支持switch / case语句; Python没有。
Ruby支持标准 expr ? val1 : val2
三元运算符; Python没有。
Ruby仅支持单继承。如果需要模仿多重继承,可以定义模块并使用mix-ins将模块方法拉入类中。 Python支持多继承而不是模块混合。
Python仅支持单行lambda函数。 Ruby块是一种lambda函数,可以是任意大的。因此,Ruby代码通常以比Python代码更实用的方式编写。例如,要在Ruby中循环遍历列表,通常会执行
collection.each do |value|
...
end
该块的工作方式与传递给collection.each
的函数非常相似。如果你在Python中做同样的事情,你必须定义一个命名的内部函数,然后将它传递给集合中的每个方法(如果列表支持这个方法):
def some_operation(value):
...
collection.each(some_operation)
这不是很好。因此,通常在Python中使用以下非功能性方法:
for value in collection:
...
在两种语言之间以安全的方式使用资源是完全不同的。这里的问题是你要分配一些资源(打开文件,获取数据库游标等),对它执行一些任意操作,然后即使发生异常也要以安全的方式关闭它。
在Ruby中,因为块很容易使用(参见#9),所以通常会将此模式编码为一个方法,该方法需要阻止任意操作在资源上执行。
在Python中,传递任意动作的函数有点笨拙,因为你必须编写一个命名的内部函数(参见#9)。相反,Python使用with
语句来安全地处理资源。有关详细信息,请参阅How do I correctly clean up a Python object?。
答案 1 :(得分:27)
我花了几个月的时间学习Python,经过6年的Ruby学习。对于这两种语言,确实没有很好的比较,所以我决定自己编写并自己写一个。现在, 主要关注函数式编程,但是既然你提到了Ruby的inject
方法,我猜我们的波长是相同的。
我希望这会有所帮助:The 'ugliness' of Python
有几点会让你朝着正确的方向前进:
您在Ruby中使用的所有函数编程优点都在Python中,而且更加容易。例如,您可以完全按照您的预期映射函数:
def f(x):
return x + 1
map(f, [1, 2, 3]) # => [2, 3, 4]
Python没有像each
那样的方法。由于您只使用each
作为副作用,因此Python中的等效项是for循环:
for n in [1, 2, 3]:
print n
当a)你必须一起处理函数和对象集合时b)当你需要使用多个索引进行迭代时,列表理解是很好的。例如,要查找字符串中的所有回文(假设您的函数p()
对于回文而言都返回true),您只需要一个列表理解:
s = 'string-with-palindromes-like-abbalabba'
l = len(s)
[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
答案 2 :(得分:10)
我的建议:不要试图了解差异。了解如何在Python中解决问题。就像对每个问题都有一个Ruby方法(它非常适用于语言的局限性和优势),有一个Python方法来解决这个问题。它们都不同。为了充分利用每种语言,你真的应该学习语言本身,而不仅仅是从一种语言到另一种语言的“翻译”。
现在,据说,差异将帮助您更快地适应并对Python程序进行1次修改。这对于开始写作来说很好。但是,尝试从其他项目中学习建筑和设计决策背后的原因,而不是语言语义背后的原因......
答案 3 :(得分:8)
我对Ruby知之甚少,但这里有一些关于你提到的事情的要点:
nil
,表示缺少值的值为None
(请注意,您要检查x is None
或x is not None
,而不是==
} - 或通过强制转换为布尔值,请参阅下一点。)None
,零号码(0
,0.0
,0j
(复数))和空集合([]
,{{1} },{}
,空字符串set()
等)被认为是假的,其他一切都被认为是真实的。""
- )显式循环。为了生成一堆没有副作用的东西,使用列表推导(或者他们的亲戚 - 懒惰的一次迭代器的生成器表达式,所述集合的dict / set comprehensions)。关于循环:你有for
,它在可迭代(!不计数)和for
上运行,它可以达到预期效果。由于对迭代器的广泛支持,更加强大。不仅几乎所有可以作为迭代器而不是列表的东西都是迭代器(至少在Python 3中 - 在Python 2中,你有两个并且默认是一个列表,遗憾的是)。有很多用于处理迭代器的工具 - while
并行迭代任意数量的迭代,zip
为您提供enumerate
(在任何可迭代,而不仅仅在列表上),甚至切片abritary(可能是大的或无限的)iterables!我发现这些使许多循环任务变得更加简单。毋庸置疑,它们可以很好地与列表推导,生成器表达式等集成。
答案 4 :(得分:6)
在Ruby中,实例变量和方法是完全不相关的,除非你明确地将它们与attr_accessor或类似的东西联系起来。
在Python中,方法只是一个特殊的属性类:一个是可执行的。
例如:
>>> class foo:
... x = 5
... def y(): pass
...
>>> f = foo()
>>> type(f.x)
<type 'int'>
>>> type(f.y)
<type 'instancemethod'>
这种差异有很多含义,例如,引用f.x指的是方法对象,而不是调用它。另外,正如您所看到的,f.x默认是公共的,而在Ruby中,实例变量默认是私有的。