Python中的所有东西都像Ruby一样是对象吗?

74

我在另一个Stack Overflow问题上读到,Python和Ruby非常相似,因为它们都关注"一切皆为对象",并且Python中的所有东西都像Ruby一样是对象。

这是真的吗?在Python中是否像Ruby一样,一切都是对象?

在这方面这两个语言有什么不同,还是它们确实是一样的?例如,您能否采取数字并执行类似于我所看到的Ruby操作:

y = 5.plus 6

在Python中可以用同样的方法吗?


当你说“对象”时,你是否指的是面向对象编程(OOP)术语?Python和Ruby都是相对初学者的语言,所以如果你实际上将问题与Smalltalk、C++或从任何特定语言抽象出来的OOP范例(理论)相关联,那么你的问题对我来说更有意义:“Python是一种纯粹的OO语言吗,即每个(数据)类型都是一个对象(或对象类)?”http://en.wikipedia.org/wiki/Object-oriented_programming - Yauhen Yakimovich
参见:https://dev59.com/0HVC5IYBdhLWcg3ww0Dr - dreftymac
并非所有东西在Ruby中都是对象。每个(合理的)值都是一个对象(也就是说,没有原始类型,甚至nil也是一个对象),但除此之外就变得更加棘手了。类是对象,方法不是。Proc是对象,块不是。(但是方法和块都可以转换为Proc)。绑定是对象,本地变量不是。等等... - Pelle
并不是所有的东西在Ruby中都是对象。每个(合理的)值都是一个对象(也就是说,没有原始类型,甚至nil也是一个对象),但除此之外就变得更加棘手了。类是对象,方法不是。Proc是对象,块不是。 (但是方法和块都可以转换为Proc)。绑定是对象,局部变量不是。等等... - undefined
8个回答

97

DiveIntoPython - 一切皆为对象

在 Python 中,所有的东西都是一个对象,几乎每个对象都有属性和方法。所有函数都有一个内置属性 __doc__,它返回函数源代码中定义的文档字符串 doc string。模块 sys 是一个对象,其中包含了(除其他外)一个名为 path 的属性。等等。

但这也引出了另一个问题,什么是对象?不同的编程语言对“对象”的定义有所不同。在某些编程语言中,“对象”意味着所有对象都必须拥有属性和方法;在其他编程语言中,“对象”意味着所有对象都可被子类化。在 Python 中,这个定义相对较宽松;有些对象既没有属性也没有方法(第三章会进一步讲解),而且并非所有对象都可以被子类化(第五章会进一步讲解)。但是,在 Python 中一切皆为对象,因为它们都可以被赋值给一个变量或作为参数传递给函数(第四章会详细讲解)。

Ruby 文档 - 从 Python 转到 Ruby

与 Python 类似,在 Ruby 中......一切皆为对象。

所以,从 Ruby 的官方网站来看,Python 中的一切都是对象。


2
+1 说得好。作为一名 Ruby 程序员,我倾向于“对象必须具有方法”的观点,但“任何东西都可以作为参数传递”的论点说得很好(我认为更能反映 Pythonista 的观点)。 - rampion
29
但是从某种意义上来说,所有的东西都可以被视为对象,因为它们可以被赋值给一个变量或者作为一个函数的参数进行传递(更多内容详见第四章)。这对我来说没有任何意义。这是否意味着Java中的int也是对象? - James McMahon
8
是的,你说得对!!上面的回答没有回答这个问题!!如果我们读一下Guido的博客,它说:“Python一个目标是使所有对象都是‘first class’。我的意思是,我希望所有可以在语言中命名的对象(例如整数,字符串,函数,类,模块,方法等)具有平等的地位。也就是说,它们可以赋值给变量,放置在列表中,存储在字典中,作为参数传递等等。” - overexchange
2
我可能还会说:“对象是指它们在CPython中使用与其他对象相同的固有结构/挂钩位置实现的”... - Owen S.
1
我认为普遍的理解是,对象是方法和字段的容器,访问这些内部方法和字段的权限由对象本身控制。也就是说,要执行方法或读/写字段,必须请求对象代为执行。我不了解Python,但它似乎可能不符合这个定义。我认为你可以创建一种语言,在运行时绝对所有内容都是如此,所有对象都包含在一个主对象中,因此即使引用相等性也可以成为主对象的一个方法。 - Didier A.
显示剩余2条评论

45

虽然Python中的所有东西都是对象,但在解析名称和与对象交互方面与Ruby不同。

例如,虽然Ruby在Object基类上提供了一个'to_s'方法,以公开该功能,但Python将其集成到字符串类型本身中-通过从中构造字符串将类型转换为字符串。而不是使用5.to_s,你可以使用str(5)

不过,不要被骗了。幕后仍有一个方法-这就是为什么这段代码有效:

(5).__str__()

实际上,这两个在本质上是相似的,但你需要以不同的方式使用它们。Python中用于类似列表和元组等序列的长度就是此原则的又一个例子 - 实际功能是基于具有特殊名称的方法构建的,但通过更简单、易于使用的接口(len函数)公开。

因此,与您在问题中编写的内容相当的Python代码为:

(5).__add__(6)

另一个重要的区别是全局函数的实现方式。在Python中,全局函数由字典表示(本地函数也是如此)。这意味着以下内容:
foo(5)

在 Python 中,相当于这样:

globals()["foo"].__call__(5)

虽然 Ruby 可以有效地完成这个任务:

Object.foo(5)

这对于编写两种语言的代码时所采用的方法有很大的影响。Ruby 库通常通过向现有类型(如 Object)添加方法来增长,而 Python 库则通常通过向给定模块添加全局函数来增长。

Python库往往通过向给定模块添加全局函数来增长。这并不完全正确。globals()["foo"]返回一个对象。__call__是一个方法,而不是全局函数。你不能做globals()["call"]。 - Unknown
我的观点是foo不是模块的方法,而是模块的属性,它碰巧是可调用的,并且导入它也将其添加到globals()中。__call__是一个方法,没错。相比之下,在Ruby中,foo是Object的一个方法。 - Katelyn Gadd
2
我试图理解为什么可以执行 "1".eq("2") => False,但不能执行 1.eq(2) => SyntaxError: invalid syntax。你的回答表明我需要括号,例如 (1).eq(2)。奇怪的是,@RichieHindle 的 1..add(2) 可以工作,但单个句点不行。这是为什么? - Matthew Cornell
1
@MatthewCornell 我认为,因为在1.add(5)的情况下,在小数点后面解释器期望找到一些数字,但是发现了_,这不是数字,因此会引发错误。然而,在1..add(5)的情况下,第二个小数点除了调用某些属性或方法外没有任何作用。 - chandola

26
“everything”这个说法有点过头了,对于Python和Ruby来说都是如此。例如,if不是“一个对象”,而是关键字,用于启动条件语句或(在Python中)在列表推导和生成器表达式中使用。热情之余发现函数、类、方法等在(比如)C ++ 中并非真正的对象,而在Ruby或Python中却是对象,这引起了这样的热情。在Ruby中可能有其他东西是对象而在Python中不是,反之亦然(代码块、正则表达式等)。

5
是的,即使在 smalltalk 中,'if' 也是块(Proc/lambda on ruby,lambdas on python,closures for language-agnostic guys)的一种方法,并且一切都是对象,它有它的关键字 true、false、nil、self、super 和 thisContext。当然,这些更像是伪变量... - Daniel Ribeiro
虽然这个答案中的示例是正确的,但在Ruby中还有一些不太明显的东西并不是对象。最为人所熟知的是:方法在Ruby中本身就不是对象。但是可以使用proc&&:define_method将它们转换为Proc(一个对象)或从Proc转换回来。 - Pelle
虽然这个答案中的示例是正确的,但在Ruby中还有一些不太明显的东西不是对象。最为人所熟知的是:方法在Ruby中本身不是对象。但是,可以使用proc&&:define_method将它们都转换为Proc对象,而Proc对象本身是一个对象。 - undefined

23

回答你的第二个问题, 是的:

>>> (1).__add__(2)
3

2
没错。甚至1. __add__(2)(注意空格)也可以使用。对于浮点数也适用:1..__add__(2) - dF.
3
@dF:您的第一个示例,在“1.”后使用空格,在3.2.3版本中对我无效=> 语法错误:无效语法。 - Matthew Cornell
5
空格应该放在数字1和小数点之间:1 .__add__(2) - Vito De Tullio

2

据我所知,Python中的所有东西都是对象。当然,原始类型和内置类型(int、long、str、float等)可以被子类化-实际上,这些类型本身就是对象。函数是对象,类是对象,甚至代码块在某种意义上也是对象... 我无法想象Python中有什么不能被视为对象的。


“#注释”是一个对象吗?这并不是批评;我只是真的很好奇。 - user5012123
1
@ocertat 不是的,至少不是我认为你的意思。注释是源代码的一个特性,但不是程序本身的一部分。当Python解析器运行时,它只是丢弃注释中的任何文本,并不对其进行操作。(然而,标准库中有一个Python源代码解析器,如果你在带有注释的源文件上运行它,它可能会产生与这些注释相对应的对象——我不记得它是否这样做了。) - David Z
1
我认为if不是一个对象。 - Brian Spiering

1
添加评论到其他人的优秀答案:所有东西都是对象,但有些(特别是字符串和数字类型)是不可变的。这意味着这些类型在赋值、参数传递等方面的行为类似于C或Java等语言中整数等不是对象的情况,并且您永远不必担心由按引用传递引起的陷阱。这是一个相当好的解决方案 :-)

1
你好,答案并不是万能的,参考资料更加全面,提供了更多的途径。例如,在Python 3.8.5中,分隔符、运算符和关键字都不是对象。stackoverflow.com/a/66374328/11554034 在那个链接中,我已经详细解释了它,请随意查看。
无论如何,下一个说法是,你可以通过以下方式纠正该语句(更正确的方式,尽管如果仍然可以更完整,则随意): "在Python中,逻辑行中除了NEWLINE、INDENT、DEDENT、空格字符、运算符、关键字或分隔符之外的所有内容都是对象。" 干杯。

0

是的,根据我的研究,Python中的所有东西都是对象。

文档如下所示:

对象是Python中数据的抽象。Python程序中的所有数据都由对象或对象之间的关系表示。

每个对象都有一个身份、类型和值。

另外,我还检查了每个值的类型以及它们是否是特定类的实例,如下所示:

from types import FunctionType

class Person:
    pass

def test():
    pass

print(type("Hello"), isinstance("Hello", str))
print(type(100), isinstance(100, int))
print(type(100.23), isinstance(100.23, float))
print(type(100 + 2j), isinstance(100 + 2j, complex))
print(type(True), isinstance(True, bool))
print(type(None), isinstance(None, type(None)))
print(type([]), isinstance([], list))
print(type(()), isinstance((), tuple))
print(type({}), isinstance({}, dict))
print(type({""}), isinstance({""}, set))
print(type(Person), isinstance(Person, type))
print(type(test), isinstance(test, FunctionType))

输出:

<class 'str'> True
<class 'int'> True
<class 'float'> True
<class 'complex'> True
<class 'bool'> True
<class 'NoneType'> True
<class 'list'> True
<class 'tuple'> True
<class 'dict'> True
<class 'set'> True
<class 'type'> True
<class 'function'> True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接