写了这么久Python,这10个冷门知识你知道几个?
Python写久了,其实大多数时候都在用那一套基础语法,if、for、class、def……但有些东西你可能从来没碰过,也没听谁提过。
不用也能写代码,但知道了,偶尔能让你写得更简洁一点,也可能看懂别人的骚操作。
今天分享10个我自己觉得挺冷门但有点意思的小知识点。
1. for循环居然也能搭配else
很多人第一次见的时候都会问:for循环为啥要加else?它不是和if配的吗?
其实for ... else语句,在循环没有被break打断的时候,会执行else里的内容。
nums = [1, 2, 3, 4, 5]
for n in nums:
if n == 10:
print("找到了")
break
else:
print("没找到")
如果列表里没有10,循环完整跑完,就会走else,输出“没找到”。
跟写个found = False然后再判断要清爽很多。尤其查找的时候挺方便。
2. :=:传说中的“海象运算符”
Python 3.8以后加了个新操作符,叫“海象运算符”,写法是:=。
它的作用是:在表达式里就完成赋值。
举个例子,你以前可能这么写:
line = input()
while line:
print(line)
line = input()
现在可以写成一行:
while (line := input()):
print(line)
虽然没快多少,但写起来确实清爽了一点。不用先写个变量,再去while里面判断。
不过也别滥用,太多海象会让代码可读性变差。
3. *args、**kwargs还能这么组合
我们知道*args和**kwargs可以接收位置参数和关键字参数,但你知道这4种方式可以混用吗?
def demo(a, b=2, *args, c=3, **kwargs):
print(a, b, args, c, kwargs)
demo(1, 10, 20, 30, c=99, d=100)
# 输出:1 10 (20, 30) 99 {'d': 100}
关键点:
*args后还能接收命名参数(比如c)**kwargs永远兜底接收其他关键字参数
写装饰器或者做接口的时候会很常用。
4. defaultdict让你少写很多判断
平时用字典的时候,总会写一堆判断:
if key not in my_dict:
my_dict[key] = []
my_dict[key].append(val)
用了defaultdict之后,完全可以一行解决:
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
不需要提前判断key在不在,没在它自己会初始化一个空列表给你。
还能指定成int、set、lambda等,挺灵活的。
5. zip(*iterable)可以“转置”二维列表
常见场景:你有个二维列表,想把行列对调。
data = [
[1, 2, 3],
[4, 5, 6]
]
transposed = list(zip(*data))
print(transposed) # [(1, 4), (2, 5), (3, 6)]
注意这里的*是把data“解包”成多个参数传进去。
这个技巧在处理CSV、表格类数据的时候特别有用。
6. __slots__:给你的类瘦个身
默认情况下,Python 给每个对象都用一个 __dict__ 来存属性,这挺灵活,但也挺占内存。
如果你只是要创建很多结构简单的小对象,可以加个 __slots__ 限制一下,就能省不少空间。
class Person:
__slots__ = ['name', 'age']
def __init__(self, name, age):
self.name = name
self.age = age
加了 __slots__ 之后,这个类的实例就只能有 name 和 age 这两个属性,而且不再用 __dict__,内存也更紧凑。
适合用在大量创建对象的场景,比如爬虫、数据处理那种。
7. collections.Counter:统计谁比它快?
以前统计列表里元素出现的次数,是不是经常这么写:
counts = {}
for item in data:
counts[item] = counts.get(item, 0) + 1
有点啰嗦。
直接用 Counter,一行搞定:
from collections import Counter
data = ['a', 'b', 'a', 'c', 'b', 'a']
c = Counter(data)
print(c) # Counter({'a': 3, 'b': 2, 'c': 1})
还能直接做加法、找最常见的元素,功能挺丰富:
print(c.most_common(1)) # [('a', 3)]
省心省力,建议常备。
8. itertools:你可能忽略的超强标准库
itertools 这个模块常被忽视,但里面藏了很多处理迭代器的利器。
举几个我经常用的:
from itertools import combinations, permutations, groupby
list(combinations([1, 2, 3], 2)) # [(1, 2), (1, 3), (2, 3)]
list(permutations([1, 2, 3], 2)) # [(1, 2), (1, 3), (2, 1)...]
groupby也很强:
from itertools import groupby
data = 'aaabbcddddd'
groups = groupby(data)
for k, g in groups:
print(k, list(g))
# 输出:
# a ['a', 'a', 'a']
# b ['b', 'b']
# c ['c']
# d ['d', 'd', 'd', 'd', 'd']
适合用在数据分组、组合问题、流式处理里。
9. sorted() + key,可以不按常理出牌排序
默认的排序太死板?用 key 就能自定义你想要的逻辑。
words = ['apple', 'banana', 'grape', 'kiwi']
# 按字符串长度排序
sorted(words, key=len)
还可以组合复杂逻辑:
data = [{'name': 'Tom', 'age': 20}, {'name': 'Amy', 'age': 18}]
sorted(data, key=lambda x: x['age'])
甚至还能倒着排、忽略大小写、按拼音排……逻辑你说了算。
10. id():看看对象在内存里长啥样
这个不常用,但调试的时候挺有帮助。
a = [1, 2, 3]
b = a
print(id(a), id(b)) # 一样
说明两个变量指向的是同一个对象。
再看这个:
a = [1, 2, 3]
b = list(a)
print(id(a), id(b)) # 不一样
虽然b = list(a)看着差不多,其实是复制了一份新的出来。
可以帮你判断浅拷贝、深拷贝、引用是不是同一个。
收个尾
今天这10个冷门小知识,有的是标准库里不常提到的宝藏,有的是Python语法里的一点“小聪明”。
你可能用不上,但知道它们总归是有好处的。 以后看到别人写的“骚代码”时,不至于一脸问号。要用的时候,翻出来就能用。
如果你也有类似的冷门知识点,欢迎在评论区给我整两个,我一定认真看,能学一手是一手!