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