Python语法辨析与补充
Python
函数与语法
统计元素相关函数
count
的使用.
l.count(1)
set()
1 | s = set() # 空集合 |
三元运算符
值1 if 条件 else 值2
max_value = x if x > y else y
字符串的填充函数
Python ljust()
方法返回一个原字符串左对齐,并使用空格(默认情况下)填充至指定长度的新字符串。如果指定的长度小于原字符串的长度则返回原字符串。eg1.ljust(50, '0')
eg.为左对齐,并且每行不足50字符用0补充eg2.ljust(50)
这是默认填充
类似的函数还有rjust()
,center()
字典
方法 | 描述 | 示例 |
---|---|---|
.keys() |
遍历键 | for key in my_dict.keys() |
.values() |
遍历值 | for value in my_dict.values() |
.items |
遍历键值对 | for key, value in my_dict.items() |
enumerate() |
遍历键和索引 | for index, key in enumerate(my_dict) |
由列表引发的拷贝问题来看底层机制
[[]]*n
和[[] for _ in range(n)]
在形式上虽然一致.但是他们的效果却有很大的差异
这是由于python对象引用机制造成的
当写 a = []
时:
- Python 会在内存中创建一个新的空列表对象
- 变量
a
实际上存储的是指向这个列表对象的引用
那么乘法列表也是同理[[]] * n
实际上做了两件事:
- 先创建
[[]]
:包含一个空列表对象(假设内存地址为0x1234
) - 乘法操作
* n
:将这个空列表的引用复制 n 次
1 | res = [ |
执行 res[0].append(1)
时:
- 不是修改
res[0]
这个引用本身,而是通过引用去修改它指向的列表对象 - 由于所有子列表都指向同一个对象,所有位置都会同步变化
那么为什么整数就没有这种问题呢?
因为整数不可变,修改时实际是让 a[0]
指向新对象,而不是修改原对象。
假设a=[1,1,1] 当执行
a[0] = 100` 时:
- 不是修改整数对象 1(因为整数是不可变的,无法修改)
- 而是让
a[0]
指向一个新的整数对象 100(新内存地址,比如0x2000
) - 其他元素仍然指向原来的整数对象
1
(0x1000
)
1 | a = [1] * 3 |
图示
1 | 错误方式 ([[]] * 3) 正确方式 (列表推导式) |
延伸到浅拷贝和深拷贝
- 直接赋值:其实就是对象的引用(别名)。将变量与内存中的值建立了联系,变量存储的是值的内存地址
a = [1,2,3]
b = a
a[0] = 0
那么b[0]
也是0,因为ab引用的是同一个地址数据.这个内存地址的指向变了 - 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
也就是子列表仍然会出现直接赋值的情况–引用的是相同的内存地址 - 深拷贝(deepcopy):copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
再触及到[:]
,切片知识的完善
在Python中,nums[:] = ...
是一种特殊的列表操作,它的作用是原地修改列表内容(即不创建新列表,直接覆盖原列表元素),而不是让变量 nums 指向一个新对象.
nums[:]
表示对列表 nums 的完整切片(从第一个元素到最后一个元素.使用赋值语句之后,右侧的值按顺序覆盖原列表的所有元素,而不是让 nums 指向一个新对象
也就是直接修改原列表的内存内容,在原地修改列表
代码示例:
1 | a = [1, 2, 3] |
补充:
对于二维数组来说,直接使用[:]
,仍然为浅复制,正确写法为
1 | example = [row[:] for row in grid] |
运算逻辑之%
余数的符号与除数一致(正负由除数决定)。
满足公式:
被除数 = 除数 × 商 + 余数
其中商是向负无穷方向取整后的整数(地板除)。
eg
1 | print(7 % 3) # 输出 1 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 loading233!