守望的麦子

如何理解 Python 中“一切皆对象”?

2018-06-20    大连    /python/2018/06/20/object.html python python

本文最近更新于 2018 年 07 月 05 日

Python 是一门优雅而健壮的编程语言,它继承了传统编译语言的强大性和通用性,同时也借鉴了简单脚本和解释语言的易用性。
Python 编程简明教程 https://wheat.at/python

在 Python 中有一句话——一切皆对象。那应该如何理解“一切皆对象”?

何为对象?

不同的编程语言以不同的方式定义“对象”。某些语言中,它意味着所有对象必须有属性和方法;另一些语言中,它意味着所有的对象都可以子类化。在 Python 中,定义是松散的,某些对象既没有属性也没有方法,而且不是所有的对象都可以子类化。但是 Python 的万物皆对象从感性上可以解释为:Python 中的一切都可以赋值给变量或者作为参数传递给函数。1

在 The Python Language Reference2 中更是具体指出3:每个对象都有标识(ID),类型和值组成。对象一旦建立,它的 ID 就不会改变;我们可以把它理解为该对象在内存中的地址。is 操作符比较两个对象的 ID;id() 函数返回一个表示对象 ID 的整数。对象的类型决定对象能够支持的操作(例如,它是否具有长度?),还定义该类型的对象可能有的值/取值范围。type() 函数返回对象的类型(它本身也是一个对象)。与 ID 一样,对象的类型也是不可以修改的。4

解释

“一切皆对象”也就是说在 Python 中下列语句其实都有一个共同点:

i = 1
s = "abc"
def foo(): pass
class C(object): pass
instance = C()
l = [1, 2, 3]
t = (1, 2, 3)

它们在 Python 解释器中执行的时候,都会在堆中新建了一个对象,然后把新建的对象绑定到变量名上:

i = 1                   #新建一个 PyIntObject 对象,绑定到 i 上
s = "abc"               #新建一个 PyStringObject 对象,绑定到 s 上
def foo(): pass         #新建一个 PyFunctionObject 对象,绑定到 foo 上
class C(object): pass   #新建一个类对象,绑定到 C 上
instance = C()          #新建一个实例对象,绑定到 instance 上
l = [1, 2, 3]           #新建一个 PyListObject 对象,绑定到 l 上
t = (1, 2, 3)           #新建一个 PyTupleObject 对象,绑定到 t 上

分析

每个对象都有一个唯一的身份标识自己,可以使用内建函数 id() 来得到,我们可以把这个值理解为该对象的内存地址:

>>> i = 1
>>> id(i)
8104016
>>> 

对象的类型决定了对象可以用来保存什么类型的值,有哪些属性和方法,可以进行哪些操作,遵循怎样的规则。可以使用内建函数 type() 来查看对象的类型(代码续上):

>>> type(i)
<type 'int'>
>>> type(type)
<type 'type'> #type 也是一种特殊的对象 type
>>> i
1
>>>

“身份标识(ID)”、“类型”和“值”随对象被创建而产生。如果对象支持更新操作,则它的值是可变的,否则为只读(数字、字符串、元组等均不可变)。只要对象还存在,这三个特性就一直存在。

所以,简单来看,i = 1 是将变量 i 和数字 3 进行连接,使 i 成为对象 3 的一个引用(可以理解为变量是到对象的内存空间的一个指针),需要注意的是:变量总是连接到对象,而不会连接到其他变量。

从概念上可以这样理解:对象是堆上分配的一个内存空间,用来表示对象所代表的值;变量是一个系统创建的元素,拥有指向对象的引用(引用是从变量到对象的指针)。

举例,当我们定义如下函数时:

>>> def hi(name = "Jason"):
        return "Hi! " + name

>>> print hi()
Hi! Jason

我们可以将函数赋值给一个变量(我们这里不使用小括号,因为我们并不准备调用 hi 函数):

>>> hello = hi
>>> hi()
'Hi! Jason'
>>> hello()
'Hi! Jason'
>>> hi
<function hi at 0x02AA3770>
>>> type(hi)
<type 'function'>
>>> type(hello)
<type 'function'>
>>> id(hi)
44709744
>>> id(hello)
44709744
>>> #hi 和 hello 属于同一类型,指向了同一个对象

调用 hi 函数:

>>> hello = hi()
>>> type(hello)
<type 'str'>
>>> id(hello)
44730208
>>> #hello 对象的类型和标识被更改

如果我们删掉 hi 函数:

>>> hello
'Hi! Jason'
>>> hi()
'Hi! Jason'
>>> del hi
>>> hi

Traceback (most recent call last):
  File "<pyshell#41>", line 1, in <module>
    hi
NameError: name 'hi' is not defined
>>> hello
'Hi! Jason'
>>> 

hi 函数不再存在,hello 变量指向的对象不受影响。

扩展阅读:


  1. 译自《Dive into Python》,原文链接 [return]
  2. 本文参考 Python 3.5.5 documentation 的 Language Reference,链接地址为 docs.python.org/3.5/reference/ [return]
  3. 原文链接 docs.python.org/3.5/reference/datamodel.html#objects-values-and-types [return]
  4. 在某些情况下,在某些可控的条件下,是可以更改对象的类型的。但它一般不是好主意,因为如果它处理不正确,可能导致一些非常奇怪的行为。 [return]
关于作者
麦子,80 后,现从事通信行业。安卓玩家一个人的书房朗读者。
MRJENGLISH
jsntn
jasonwtien
jasonwtien
更多…… /about.html

最近更新: