对象是Python对数据的抽象,在Python程序中,所有的数据,都可以由对象或对象之间的关系表示。
从某种意义上说,根据冯·诺依曼的“存储程序”的模型,代码也由对象表示。
在Python中,每个对象都有3个核心部分:
1)身份/标识(identity):对象的身份标识一旦被创建,在整个对象的生命周期都是不会改变的,CPyhon中将对象在内存中的存储地址,作为对象的身份标识。
前面已经用到过,使用id()函数可以返回一个表示对象身份标识的整数。
2)类型(type):对象的类型决定了该对象能够支持的运算、操作,以及该对象的取值范围。如同对象的身份标识一样,对象的类型在对象的整个生命周期中也是不可改变的。
通过type()函数可以返回一个对象的类型(它本身也是一个对象)。
3)值(value):某些对象的值可能会发生变化。值可以变的对象被称为是可变对象;而一旦创建后,其值就不可更改的对象称为不可变对象。
需要注意的是,我们知道数字、字符串、元组是不可变对象。但是,对象的不可变性是很微妙的,对象的不可变性与具有不可改变的值,并不是等价的。比如,元组中存储了可变对象的引用,则其元素是可更改的,但是元组对象本身仍然是不可变的对象。
从一切都是对象的角度来看,所谓的容器对象,其实是这些对象的值一般是其他对象的引用。
此外,如同前面的文章中已然提到过的:对于不可变类型,计算新值的操作,实际上可能返回对具有相同类型和值的任何现有对象的引用。而,对于不可变对象,这种操作则是不允许的。
输出结果:
一切皆对象不同于静态类型的编程语言,Python中的面向对象更加彻底,可以说一切皆对象。
前面已经提到,对象的3个核心组成:身份标识(id)、类型(type)、值。其中,通过函数type()我们可以看到对象的类型,也就是用于实例化这个对象的类。
接下里,我们通过对各种实体调用type()函数,来验证Python中一切皆对象。
数字是对象
对象可以有自己的属性和方法:
字符串是对象
内置类型也是对象
可以看到,内置类型int,也是对象,这个对象的类型是type,也有自己的id;内置类型str也是类似的。
函数和类也是对象
输出结果:
函数对象和类对象,也有对应的属性和方法:
输出结果:
可以看到,函数的__code__属性是一个code对象,也就是开篇提到的代码对象……
简单延伸一下:
Python中,代码对象和函数对象之间的区别在于,函数对象包含对函数全局变量(定义它的模块)的显式引用,而代码对象不包含上下文;默认参数值也存储在函数对象中,而不是代码对象中(因为它们表示在运行时计算的值)。与函数对象不同,代码对象是不可变的,并且不包含对可变对象的引用(直接或间接)。
总结从上面示例代码中可以看出,内置类型int、str,以及自定义的类MyClass,这些类对象,都是由type这个类对象进行实例化的。那么type这个类对象又是谁实例化的呢?
你没有看错,type类对象是由自己实例化的……
虽然,本文的内容有点绕,但是,必须说的是,Python中的“一切皆对象”的理念,使得Python具有高度的灵活性和一致性。无论是简单的数据类型还是复杂的函数和类,它们都是对象,并可以进行统一的操作。这种设计哲学使得Python代码更加简洁、优雅和易于维护。
当更多地将Python应用于实际场景之后,应该会有更深刻的体会。