show | version | enable_checker |
---|---|---|
step |
1.0 |
true |
- 上次研究了赋值运算
- 直接用列表引用的地址赋值
- 造成两个列表指向同一个对象
- 一荣俱荣
- 一损俱损
- 所有操作都会作用到一个对象上
- 造成两个列表指向同一个对象
- 如果将列表副本赋给变量
- 这两个列表变量指向不同的对象
- 互不影响
- 制作副本的3种方法
- copy拷贝
- list构造
- slice切片
- 直接用列表引用的地址赋值
- 赋值运算符号=很简单
- 但是由于等号右边的对象不同
- 还是有很多细节的
- 还有什么好玩的细节呢?
- 列表可以做加法吗?🤔
- 比如l1 + l2
- 字符串可以进行加法和乘法的运算
- 列表也能做加法吗?
- 再试试字符串列表
- 加是可以加的
- 但是加的结果
- 没有赋给任何变量
- 随着寄存器下次被赋值
- 垃圾回收了
- 没了
- 把加法的结果赋给 l3
- 那么这个加法的结果就有变量名进行引用了
- 就不会被垃圾回收了
- 什么是垃圾回收呢?
-
之前的语言
- 分配和释放内存都是靠成员完成的
- 容易忘记释放内存
- 容易造成内存泄漏
- 占用越来愈多
- 最后崩溃
-
python 解释器
- 定期观察分配给变量的空间
- 是否还有变量在引用
- getrefcount
- 没有引用的话 就垃圾回收
- 定期观察分配给变量的空间
- 垃圾回收
- garage collection
- l1、l2、l3 三个变量引用地址相同吗?
- 用id输出地址
- 这三个变量地址都不相同
- 三块空间都有变量引用
- 都不会被回收
- 可以把列表求和的结果赋给 l1 么?
- 赋值之后
- l1 不再 指向原来的地址
- 而是指向和的地址
- l1 = l1 + l2
- 是不是就是l1 += l2呢?
- 从求和结果来看
- l1 = l1 + l2
- l1 += l2
- 两者一致
- += 也叫做 增强赋值运算
- augmented assignment
- 但是从引用地址来看
- += 会保留l1原来引用的地址
- 而l1 = l1 + l2 中l1 获得一个新地址
- 这效果就很像对于切片赋值
- 想要在列表尾部接出新列表
- 首先要找到列表尾部的位置
- 用len(a)得到a的长度为3
- a[3:]就是尾部的空列表
- 这里使用切片 a[len(a):]
- 其实就是在 a 的最后一个元素后面再追加列表 b
- 然后 a 就是被扩展 extend 了
- 变量引用情况如何呢?
- 对l1尾部切片赋值
- 不会改变l1引用的地址
- 这个时候其实有个新函数 extend
- extend
- 把参数里面的列表
- 循环地放到extend方法的主体后面
- 有三种方式可以扩充列表
- 并保留原来列表引用地址
- l1 += l2
- l1[-1:] = l2
- l1.extend(l2)
- 还有一种方式可以得到新的引用地址
- l1 = l1 + l2
- 效率如何呢?
- 加法运算效率最低
- 是新建一个列表
- 然后把 l1 的列表项都拿过来
- 再把 l2 的列表项都拿过来
- 最后把相加结果赋给 l1
- 效率不如extend和切片赋值
- 那这个 extend 和 append
- 有什么区别呢?
- 操作对象不同
- append
- 是为原始列表添加新元素
- 添加的是一个列表项
- extend
- 是用新列表扩展原始列表
- 添加的是若干新元素
- 这三个函数都是插入列表项
- 有什么区别呢?
- 这次我们了解了列表的加法
- 加法
- 加法的本质是将两个列表拼接
- 并将结果位置赋给帧(frame)上的变量来引用
- 对于两个列表求和并赋值有4种做法
- l1 = l1 + l2
- l1 += l2
- l1[-1:] = l2
- l1.extend(l2)
- 上述四种方法结果相同
- 但是稍有区别
- 第一种l1 = l1 + l2
- 会改变l1 所引用的地址
- 后三种不改变地址
- 第四种l1.extend(l2)
- 效率最高
- 在当前列表位置后继续扩展列表
- 第一种l1 = l1 + l2
- 但是稍有区别
- 既然列表有加法
- 那列表可以有乘法吗?🤔
- 下次再说 👋