【补充】Python之一切皆对象
【1】一切皆对象
- Python中的一切都被视为对象。
- 在Python中,每个值(包括数字、字符串、函数等)都是一个对象
- 并且每个对象都属于特定的类(class)。
- 类定义了对象的属性和行为。
- 因此,可以说Python是一种面向对象的编程语言。
- 对象是类的实例化结果
- 可以通过调用类来创建对象。
- 例如,可以使用类名后跟括号来创建一个对象:
class MyClass:
pass
obj = MyClass()
-
在上面的例子中
- 类
MyClass
是对象obj
的模板- 我们可以使用它来创建任意数量的对象。
- 每个对象都具有相同的属性和方法
- 但其内部数据可能会有所不同。
- 类
-
由于一切皆对象,因此对象可以作为参数传递给函数,也可以赋值给变量。
-
这使得Python具有动态性和灵活性,可以方便地进行编程和扩展。
- 总结起来
- Python中的一切都是对象
- 对象是类的实例化结果
- 每个对象都具有相应的属性和方法
- 从而实现了面向对象编程的特性。
【2】type 和 object的关系
a = int(2)
a = int(2)
创建了一个int
类型的对象。int
是一个类,具体的实现是由C语言实现的,在Python中被称为内置类型。- 如果写了pass,看不到源码 - 实现是由C语言实现的
- 有一部分的代码时可以看到的 - 重写方法
print(type(1))
# <class "int">
print(type(int))
# <class "type">
print(type(dict))
# <class "type">
print(type(type))
# <class "type">
print(type(object))
# <class "type">
- type是一个类:
- 在Python中,type本身也是一个类,它是所有对象类型的元对象(metaclass)。
- 可以将type看作是创建类的类,通过调用type()可以创建新的类。
- 类型对象是type的实例:
- 在Python中,int、dict等类型都是type类的实例
- 这意味着它们的类型也是type。
- 继承关系(type 继承了 object/type 是 object 的类):
- int、dict等类型并不是直接继承自object,而是通过继承type来间接继承object。
- 也就是说,type是int、dict等类型的元类(metaclass)
- 而object是type的超类。
- type是自己的类(type 是 type自己的类):
- type类本身也是一个对象,可以说type是type的实例。
- 这是因为type是其自身的元类。
- 所有类,除了object。都继承自object,包括type
- int、dict都是 type 类的对象
- int、dict 继承了 object
- type 和 object的关系
- type 是 object 的类
- type 继承了 object
- type 是 type自己的类
【3】一切皆对象的好处
(1)详解
- 统一的操作方式:
- 由于一切皆对象,不论是数字、字符串、函数还是其他类型的对象,都可以使用相同的方式进行操作和访问。
- 这样可以简化代码并提高可读性,不需要记住不同类型之间的特定操作规则。
- 灵活的赋值和传参:
- 在Python中,变量实际上是指向对象的引用,而不是直接存储值本身。
- 这意味着可以将一个变量赋值给另一个变量,这两个变量将指向同一个对象。
- 无论对象是什么类型,都可以通过赋值进行传递和共享数据,这种灵活性使得编写和使用函数更加简单。
- 动态特性:
- Python是一门动态语言,对象的类型可以在运行时改变。
- 通过修改对象的属性或者动态添加方法,可以根据需要改变对象的行为。
- 这种动态特性使得Python非常灵活,并且适合进行编写脚本和快速开发。
- 方便的扩展性:
- 由于一切皆对象,可以很方便地扩展现有对象的功能。
- 通过继承、组合和动态添加属性和方法,可以创建新的对象类型,并根据实际需求来定制功能。
- 内省和元编程:
- 一切皆对象的特性使得Python拥有强大的内省能力,可以在运行时获取对象的信息、属性和方法。
- 这种内省能力结合元编程的概念,可以实现高级的动态代码生成和修改,从而扩展Python语言本身。
(2)示例
-
在Python中,变量实际上是名称和对象之间的绑定关系。
-
当我们使用赋值语句给一个变量赋值时
- 实际上是将该变量与一个对象关联起来,并指向该对象在内存中的地址。
-
不同类型之间的变量直接可以相关赋值
- 其实本质,变量都是指向了一个内存地址
-
a = 100
a = "xxx"
- 首先,Python解释器会创建一个整数对象,并将其存储在内存中的某个地址上。
- 然后,将变量名a与该地址进行绑定,使得a指向这个整数对象。
- 其次,Python解释器会创建一个字符串对象,并将其存储在内存中的另一个地址上。
- 然后,将变量名a重新与新的地址进行绑定,使得a指向这个字符串对象。
- 这说明了Python中变量的本质是指向内存地址的指针。
- 通过赋值语句,我们可以修改变量的指向,使其指向不同类型的对象。
- 总结来说
- 变量在Python中本质上是指向内存地址的指针。
- 通过赋值语句,我们可以修改变量的指向,使其指向不同类型的对象。
【4】深浅拷贝问题引入
在Python中,深拷贝和浅拷贝是用于复制对象的两种不同的方式。
l = [1, 2, 3, [4, 5, 6, ]]
l2 = l
print(l2 is l)
# True
- 通过
- 将
l2
赋值为l
- 实际上是将
l2
和l
指向相同的内存地址。
- 将
- 所以
l2 is l
的结果为True- 表示它们是同一个对象的两个引用。
- 因此
- 对
l2
或l
的修改都会影响到另一个。
- 对
(1)浅拷贝
from copy import copy
l3 = copy(l)
print(l3 is l)
# False
l3[3][1] = 999
print(l)
# [1, 2, 3, [4, 999, 6]]
print(l3)
# [1, 2, 3, [4, 999, 6]]
- 使用
copy()
函数进行浅拷贝时- 创建了一个新的列表对象
l3
- 并复制了原始列表
l
中的元素。
- 并复制了原始列表
- 这意味着
l3
和l
是两个独立的对象- 分别指向不同的内存地址。
- 创建了一个新的列表对象
- 然而,对于嵌套的可变对象(如列表)
- 浅拷贝只会复制其引用
- 而不会创建新的内存空间。
- 因此,
l3
中的嵌套列表仍然指向相同的地址- 所以对
l3
中嵌套的列表进行修改 - 也会影响到原始的列表
l
。
- 所以对
(2)深拷贝
from copy import deepcopy
l4 = deepcopy(l)
l4[3][1] = 888
print(l)
# [1, 2, 3, [4, 5, 6]]
print(l4)
# [1, 2, 3, [4, 888, 6]]
- 通过使用
deepcopy()
函数进行深拷贝- 会递归地复制嵌套对象,包括嵌套列表。
- 这意味着在深拷贝操作中
- 不仅会创建一个新的顶层列表对象
l4
- 还会创建一个新的嵌套列表对象
- 其值与原始列表中的值相同。
- 不仅会创建一个新的顶层列表对象
- 因此
- 在对
l4
中的嵌套列表进行修改时 - 并不会影响到原始的列表
l
- 它们指向不同的内存地址。
- 在对
(3)小结
- 综上所述
- 浅拷贝只复制顶层对象
- 而深拷贝会递归复制整个对象结构。
- 在涉及到可变对象嵌套的情况下
- 深拷贝是一种更安全的选项
- 因为它可以确保对新对象的修改不会影响原始对象。
【5】深浅拷贝问题详解
- 深拷贝和浅拷贝是常用的操作,它们在处理对象和数据结构时非常有用。
- 让我们详细解释深拷贝和浅拷贝的概念,并结合案例进行演示。
(1)深拷贝:
- 深拷贝是指创建一个新的对象,该对象与原始对象完全独立。
- 换句话说,它会递归地复制所有嵌套对象,包括它们的内容,以便我们在修改新对象时不会影响到原始对象。
- 下面是一个示例
- 演示了如何使用
copy
模块中的deepcopy()
函数进行深拷贝:
- 演示了如何使用
import copy
list1 = [1, 2, [3, 4]]
list2 = copy.deepcopy(list1)
- 在这个例子中,我们创建了一个列表
list1
,其中包含一个嵌套列表。 - 通过调用
deepcopy()
函数并将list1
作为参数传递给它,我们可以创建一个名为list2
的新对象,它是list1
的深拷贝。 - 现在,我们来演示深拷贝是如何避免原始对象的修改的:
list2[0] = 999
print(list1) # 输出: [1, 2, [3, 4]]
print(list2) # 输出: [999, 2, [3, 4]]
- 可以看到,尽管我们修改了
list2
的第一个元素,但list1
保持不变。 - 这是因为
list1
和list2
是独立的对象,它们各自占用着不同的内存空间。
(2)浅拷贝:
- 浅拷贝是指创建一个新对象,并将原始对象的元素复制到新对象中。
- 然而
- 如果原始对象包含可变的对象(如列表)
- 则新对象中的这些元素仍然与原始对象中相应元素共享相同的内存地址。
- 下面是一个示例
- 演示了如何使用
copy
模块中的copy()
函数进行浅拷贝:
- 演示了如何使用
import copy
list1 = [1, 2, [3, 4]]
list2 = copy.copy(list1)
- 在这个例子中
- 我们使用
copy()
函数创建了list1
的浅拷贝list2
。
- 我们使用
- 让我们来看一下浅拷贝在修改可变对象时的行为:
list2[0] = 999
list2[2][0] = 777
print(list1) # 输出: [1, 2, [777, 4]]
print(list2) # 输出: [999, 2, [777, 4]]
- 可以看到
- 当我们修改
list2
中的第一个元素时 - 只有
list2
受到影响 - 而
list1
保持不变。
- 当我们修改
- 但是
- 当我们修改
list2
中嵌套列表的元素时 list1
也会随之改变。
- 当我们修改
- 这是因为浅拷贝只复制了列表的引用
- 而没有创建新的内存空间来存储嵌套列表。
(3)综上所述
-
深拷贝和浅拷贝在处理对象和数据结构时有不同的行为:
-
深拷贝创建一个完全独立的对象,递归地复制所有嵌套对象。
-
浅拷贝创建一个新对象,但它共享原始对象中可变对象的引用。
-