一, is == id 用法
在 Python 中, id 是内存地址, 你只要创建一个数据 (对象) 那么就会在内存中开辟一个空间, 将这个数据临时加载到内存中, 这个空间有一个唯一标识, 就好比是身份证号, 标识这个空间的叫做内存地址, 也就是这个数据 (对象) 的 id, 那么你可以利用 id()去获取这个数据的内存地址:
- name = 'Dylan'
- print(id(name)) # 4319709032
== 是比较两边的数值是否相等, 其反回的结果是 True 或 False.
is 是比较两边的内存地址是否相等, 如果内存地址相等, 那么两边所指向是同一个内存地址. 其反回的结果是 True 或 False.
- name = ['Dylan']
- name2 = ['Dylan']
- print(name is name2) # False
- print(name == name2) # True
- print(id(name)) # 4387384328
- print(id(name2)) # 4387382920
- # 这里表示: name name2 数值是一样的, 但却不是同一个内存地址.
所以: 如果内存地址相同, 那么值肯定相同, 但是如果值相同, 内存地址不一定相同.
二, 代码块
Python 程序是由代码块构造的, 块是一个 python 程序的文本, 他是作为一个单元执行的.
代码块: 一个模块, 一个函数, 一个类, 一个文件等都是一个代码块.
作为交互方式输入的每个命令都是一个代码块.
什么是交互方式?
就是咱们在 cmd 中进入 Python 解释器里面, 每一行代码都是一个代码块.
三, 同一代码块下的缓存机制
前提条件: 同一个代码块内.
机制内容: Python 在执行同一个代码块的初始化对象的命令时, 会检查是否其值是否已经存在, 如果存在, 会将其重用. 换句话说: 执行同一个代码块时, 遇到初始化对象的命令时, 他会将初始化的这个变量与值存储在一个字典中, 在遇到新的变量时, 会先在字典中查询记录, 如果有同样的记录那么它会重复使用这个字典中的之前的这个值. 所以在你给出的例子中, 文件执行时 (同一个代码块) 会把 i1,i2 两个变量指向同一个对象, 满足缓存机制则他们在内存中只存在一个, 即: id 相同.
适用对象: int(float),bool,str.
具体细则:
int(float): 任何数字在同一代码块下都会复用.
bool:True 和 False 在字典中会以 1,0 的方式存在, 并且复用.
str: 几乎所有的字符串都会符合缓存机制.
优点: 提升性能, 节省内存.
不同代码块下的缓存机制(小数据池)
前提条件: 不同代码块内.
机制内容: Python 自动将 - 5~256 的整数进行了缓存, 当你将这些整数赋值给变量时, 并不会重新创建对象, 而是使用已经创建好的缓存对象.
python 会将一定规则的字符串在字符串驻留池中, 创建一份, 当你将这些字符串赋值给变量时, 并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象.
其实, 无论是缓存还是字符串驻留池, 都是 python 做的一个优化, 就是将~ 5-256 的整数, 和一定规则的字符串, 放在一个'池'(容器, 或者字典)中, 无论程序中那些变量指向这些范围内的整数或者字符串, 那么他直接在这个'池'中引用, 言外之意, 就是内存中之创建一个.
适用对象: int(float),bool,str.
具体细则:
int(float): 那么大家都知道对于整数来说, 小数据池的范围是 - 5~256 , 如果多个变量都是指向同一个 (在这个范围内的) 数字, 他们在内存中指向的都是一个内存地址.
bool:True 和 False 在字典中会以 1,0 的方式存在, 并且复用.
str: 满足规则的字符串.
优点: 提升性能, 节省内存.
总结:
面试题考.
回答的时候一定要分清楚: 同一个代码块下适用一个缓存机制. 不同的代码块下适用另一个缓存机制(小数据池)
小数据池: 数字的范围是 - 5~256.
缓存机制的优点: 提升性能, 节省内存.
四, 集合(了解)
集合是无序的, 不重复的数据集合, 它里面的元素是可哈希的 (不可变类型), 但是集合本身是不可哈希(所以集合做不了字典的键) 的.
集合最重要的两点:
去重, 把一个列表变成集合, 就自动去重了.
关系测试, 测试两组数据之前的交集, 差集, 并集等关系.
集合和字典
集合的创建
- # 方法一
- set1 = set({
- 'name', 'Dyaln', 'age', 111, 434
- })
- # 方法二
- set1 = {
- 'name', 'Dyaln', 'age', 111, 434
- }
字典和集合的格式:
- # 字典
- dic = {
- 'name':'Dylan', 'age': 18
- }
- # 集合
- set1 = {
- 'name', 'age', 18, False, True,
- }
空字典:
- dic = {
- }
- # 或者
- {
- }
- print({
- }, type({
- })) # {
- } <class 'dict'>
空集合:
- set()
- print(set(), type(set())) # set() <class 'set'>
集合的有效性:
- set1 = {[1, 3, 5], 3, {'name': 'Dylan'}}
- print(set1)
- # 报错
- File "/Users/yaoyaoba/Full_stack_22/day06 / 练习. py", line 24, in <module>
- set() <class 'set'>
- set1 = {[1, 3, 5], 3, {'name': 'Dylan'}}
- TypeError: unhashable type: 'list'
- # 集合内的元素必须是 可合希类型(不可变数据类型)
集合的操作
增
- set.add()
- set1 = {
- 'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'
- }
- set1.add('xx')
- print(set1) # {
- 'xiaowang', 'xx', 'age', 'yaoyao', 'name', 'Dylan'
- }
set.update() 迭代增加(有重复的会自动除去)
- set1 = {
- 'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'
- }
- set1.update('abcdedfdaefdafdsa')
- print(set1) # {
- 'yaoyao', 'age', 'd', 'e', 'a', 'Dylan', 'xiaowang', 'b', 'f', 'c', 'name', 's'
- }
删
set.remove() 按元素删除
- set1 = {
- 'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'
- }
- set1.remove('age')
- print(set1) # {
- 'xiaowang', 'yaoyao', 'Dylan', 'name'
- }
set.pop() 随机删除
- set1 = {
- 'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'
- }
- set1.pop()
- print(set1) # {
- 'yaoyao', 'age', 'xiaowang', 'Dylan'
- }
set.clear() 清空集合
- set1 = {
- 'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'
- }
- set1.clear()
- print(set1) # set()
del set 删除集合
- set1 = {'name', 'Dylan', 'xiaowang', 'yaoyao', 'age'}
- del set1
- print(set1) # 会报错, 因为己经没有这个集合了
- # 报错信息如下:
- Traceback (most recent call last):
- File "/Users/yaoyaoba/Full_stack_22/day06 / 练习. py", line 28, in <module>
- print(set1) # 会报错, 因为己经没有这个集合了
- NameError: name 'set1' is not defined
集合的其它操作
交集.(& 或者 intersection)
- set1 = {
- 1, 2, 3, 4, 5
- }
- set2 = {
- 4, 5, 6, 7, 8
- }
- print(set1 & set2) # {
- 4, 5
- }
并集.(| 或者 union)
- set1 = {
- 1, 2, 3, 4, 5
- }
- set2 = {
- 4, 5, 6, 7, 8
- }
- print(set1 | set2) # {
- 1, 2, 3, 4, 5, 6, 7, 8
- }
差集.(- 或者 difference)
- set1 = {
- 1, 2, 3, 4, 5
- }
- set2 = {
- 4, 5, 6, 7, 8
- }
- print(set1 - set2) # {
- 1, 2, 3
- }
反交集. (^ 或者 symmetric_difference)
- set1 = {
- 1, 2, 3, 4, 5
- }
- set2 = {
- 4, 5, 6, 7, 8
- }
- print(set1 ^ set2) # {
- 1, 2, 3, 6, 7, 8
- }
子集与超集
- set1 = {
- 1,2,3
- }
- set2 = {
- 1,2,3,4,5,6
- }
- print(set1 <set2)
- print(set1.issubset(set2)) # 这两个相同, 都是说明 set1 是 set2 子集.
- print(set2> set1)
- print(set2.issuperset(set1)) # 这两个相同, 都是说明 set2 是 set1 超集.
列表去重
- l1 = [1,'Dylan', 1, 2, 2, 'Dylan',2, 6, 6, 3, 'Dylan', 4, 5]
- # set1 = set(l1)
- # l1 = list(set1)
- # print(l1)
- # 用处: 数据之间的关系, 列表去重.
五, 深浅 copy
copy 其实就是复制一份, 也就是所谓的抄一份. 深浅 copy 其实就是完全复制一份, 和部分复制一份的意思.
先看赋值运算
- l1 = [1, 2, 3, ['Dylan', 'age']]
- l2 = l1
- l1.append(456)
- print(l1) # [1, 2, 3, ['Dylan', 'age'], 456]
- print(l2) # [1, 2, 3, ['Dylan', 'age'], 456]
- print(id(l1)) # 4387382920 内存地址是一样的
- print(id(l2)) # 4387382920 内存地址是一样的
对于赋值运算来说, l1 与 l2 指向的是同一个内存地址, 所以它们是完全一样的, l1,l2 指向的是同一个列表, 任何一个变量对列表进行改变, 剩下那个变量在使用列表之后, 这个列表就是发生改变之后列表.
浅拷贝 copy
- l1 = [1, 2, 3, ['Dylan', 'age']]
- l2 = l1.copy()
- print(id(l1)) # 4335892104
- print(id(l2)) # 4335903304
- # 这说明, 通过 copy 出来的新列表, 在内存中又开辟了一块新的内存空间, 两者间不是指向的同一个列表.
- # 但是, 如果再做如下操作你会发现什么?
- print(id(l1[-1])) # 4370607112
- print(id(l2[-1])) # 4370607112
- # 你会发现, 咦? 内存地址是一样的, 说明是同一个数据.
由此我们可以得知, 浅拷贝其实只是拷贝了一个列表的外壳.
对于浅 copy 来说, 只是在内存中重新创建了开辟了一个空间存放一个新列表, 但是新列表中的元素与原列表中的元素是公用的.
这里还有一个问题:
当改变列表中的不可变数据类型时, 新列表中的内容是不会一同被更改的, 因为它是可哈希数据类型, 如列表中, 可变数据类型被列改或增删改, 则新列表会一同更改.
深拷贝 deepcopy
- import copy
- l1 = [1, 2, 3, ['Dylan', 'age']]
- l2 = copy.deepcopy(l1)
- print(id(l1)) # 4343088456
- print(id(l2)) # 4370618248
- # 这说明, 通过 copy 出来的新列表, 在内存中又开辟了一块新的内存空间, 两者间不是指向的同一个列表.
- print(id(l1[-1])) # 4379005512
- print(id(l2[-1])) # 4379005832
- # 咦? 内存地址不一样了, 说明不是同一个数据了.
- print(id(l1[0])) # 4305226112
- print(id(l2[0])) # 4305226112
- # 哎我去! 又一样了, 咋回事儿?
深 copy 的特性就是将可变的数据类型在内存中重新创建一份, 而不可变的数据类型则沿用之前的.
但, 同样如浅拷贝那样, 不可变的数据类型, 即便内存地址相同, 当你改变他时, 新列表也不会一同被更改, 只因为他是不可变数据类型(可哈希).
相关面试题
- l1 = [1, 2, 3, [22, 33]]
- l2 = l1[:]
- l1[-1].append(666)
- print(l1) # [1, 2, 3, [22, 33, 666]]
- print(l2) # [1, 2, 3, [22, 33, 666]]
浅 copy: list dict: 嵌套的可变的数据类型是同一个.
深 copy: list dict: 嵌套的可变的数据类型不是同一个 .
来源: https://www.cnblogs.com/guanshou/p/12046854.html