Python

函数与语法

统计元素相关函数

count的使用.

l.count(1)

set()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
s = set()              # 空集合
s = set([1, 2, 3]) # 从列表创建 → {1, 2, 3}
s = set("hello") # 从字符串创建 → {'h', 'e', 'l', 'o'}


s = {1, 2}
s.add(3) # 添加单个元素 → {1, 2, 3}
s.update([4, 5]) # 批量添加元素 → {1, 2, 3, 4, 5}


s.remove(3) # 删除元素,若不存在会报 KeyError
s.discard(3) # 删除元素,若不存在不会报错
s.pop() # 随机删除并返回一个元素(因集合无序)
s.clear() # 清空集合 → set()


a = {1, 2, 3}
b = {3, 4, 5}
# 并集
print(a | b) # {1, 2, 3, 4, 5}
print(a.union(b)) # 同上

# 交集
print(a & b) # {3}
print(a.intersection(b))

# 差集(在 a 中但不在 b 中)
print(a - b) # {1, 2}
print(a.difference(b))

# 对称差集(仅在 a 或 b 中,不同时存在)
print(a ^ b) # {1, 2, 4, 5}
print(a.symmetric_difference(b))

三元运算符

值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 实际上做了两件事:
  1. 先创建 [[]]:包含一个空列表对象(假设内存地址为 0x1234
  2. 乘法操作 * n:将这个空列表的引用复制 n 次
1
2
3
4
5
res = [
0x1234, # 指向同一个内存地址
0x1234,
0x1234
]

执行 res[0].append(1) 时:

  • 不是修改 res[0] 这个引用本身,而是通过引用去修改它指向的列表对象
  • 由于所有子列表都指向同一个对象,所有位置都会同步变化

那么为什么整数就没有这种问题呢?

因为整数不可变,修改时实际是让 a[0] 指向新对象,而不是修改原对象。
假设a=[1,1,1] 当执行 a[0] = 100` 时:

  1. 不是修改整数对象 1(因为整数是不可变的,无法修改)
  2. 而是让 a[0] 指向一个新的整数对象 100(新内存地址,比如 0x2000
  3. 其他元素仍然指向原来的整数对象 10x1000
1
2
3
a = [1] * 3
a[0] = 100 # 修改的是引用,不会影响其他元素
print(a) # 输出 [100, 1, 1]

图示

1
2
3
4
5
错误方式 ([[]] * 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
2
3
4
5
6
7
8
9
10
11
12
13
a = [1, 2, 3]
b = a

# 普通赋值:让 a 指向新列表
a = [4, 5, 6]
print(a) # 输出: [4, 5, 6]
print(b) # 输出: [1, 2, 3](b 仍然指向原列表)

# 切片赋值:原地修改原列表
a = [1, 2, 3]
a[:] = [4, 5, 6]
print(a) # 输出: [4, 5, 6]
print(b) # 输出: [4, 5, 6](b 仍然指向原列表,但内容已被修改)

补充:
对于二维数组来说,直接使用[:],仍然为浅复制,正确写法为

1
example = [row[:] for row in grid]

运算逻辑之%

余数的符号与除数一致(正负由除数决定)。
满足公式:
被除数 = 除数 × 商 + 余数
其中商是向负无穷方向取整后的整数(地板除)。
eg

1
2
3
4
5
6
7
8
9
10
print(7 % 3)   # 输出 1
# 计算过程:3 × 2 = 6 → 余数 = 7 - 6 = 1
print(-7 % 3) # 输出 2
# 计算过程:3 × (-3) = -9 → 余数 = -7 - (-9) = 2
print(7 % -3) # 输出 -2
# 计算过程:-3 × (-3) = 9 → 余数 = 7 - 9 = -2(符号与除数-3一致)
print(-7 % -3) # 输出 -1
# 计算过程:-3 × 2 = -6 → 余数 = -7 - (-6) = -1(符号与除数-3一致)
print(5.5 % 2.5) # 输出 0.5
print(-5.5 % 2.5) # 输出 2.0(余数符号与除数2.5一致)