守望的麦子

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

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

本文最近更新于 2018 年 7 月 5 日

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 中下列语句其实都有一个共同点:

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

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

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

##分析##

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

1 >>> i = 1
2 >>> id(i)
3 8104016
4 >>> 

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

1 >>> type(i)
2 <type 'int'>
3 >>> type(type)
4 <type 'type'> #type 也是一种特殊的对象 type
5 >>> i
6 1
7 >>>

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

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

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

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

1 >>> def hi(name = "Jason"):
2         return "Hi! " + name
3 
4 >>> print hi()
5 Hi! Jason

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

 1 >>> hello = hi
 2 >>> hi()
 3 'Hi! Jason'
 4 >>> hello()
 5 'Hi! Jason'
 6 >>> hi
 7 <function hi at 0x02AA3770>
 8 >>> type(hi)
 9 <type 'function'>
10 >>> type(hello)
11 <type 'function'>
12 >>> id(hi)
13 44709744
14 >>> id(hello)
15 44709744
16 >>> #hi 和 hello 属于同一类型,指向了同一个对象

调用 hi 函数:

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

如果我们删掉 hi 函数:

 1 >>> hello
 2 'Hi! Jason'
 3 >>> hi()
 4 'Hi! Jason'
 5 >>> del hi
 6 >>> hi
 7 
 8 Traceback (most recent call last):
 9   File "<pyshell#41>", line 1, in <module>
10     hi
11 NameError: name 'hi' is not defined
12 >>> hello
13 'Hi! Jason'
14 >>> 

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

扩展阅读:

  1. 译自《Dive into Python》,原文链接 

  2. 本文参考 Python 3.5.5 documentation 的 Language Reference,链接地址为 docs.python.org/3.5/reference/ 

  3. 原文链接 docs.python.org/3.5/reference/datamodel.html#objects-values-and-types 

  4. 在某些情况下,在某些可控的条件下,是可以更改对象的类型的。但它一般不是好主意,因为如果它处理不正确,可能导致一些非常奇怪的行为。 

关于作者
麦子,80 后,现从事通信行业。安卓玩家一个人的书房朗读者。
MRJENGLISH
jsntn
jasonwtien
jasonwtien
更多…… /about.html

最近更新: