1. 跳出双层循环用for…else…
for i in range(5):
for j in range(5):
print(i, j)
if i == 3 and j == 3:
break
else:
continue
break
如果当次循环执行了break,那么else不会执行。(没有被break的程序才会走else流程)
当i和j不同时等于3时,就会执行内层for循环的else
语句,然后执行continue
当i和j都等于3时,就是执行break
跳出内层的for循环,在执行外层for循环的break
跳出外层循环。
2. 使用csv将数据写入文件
当我在写爬虫是,通常会把数据写入成csv格式,即逗号分隔符,但这里有个问题是如果源数据中本身就有英文逗号,那就会使原来的混淆,所以我们可以用csv模块来写入csv。
例如:
with open('data.csv', 'a')as f: # 将数据保存到文件中
writer = csv.writer(f, lineterminator='\n')
writer.writerow([n, num, status, name, indication, subject])
在这里如果不加关键字参数lineterminator='\n'
时,会发现每写入一行,便多一个空行。而我们可能并不需要这些空行。因为默认lineterminator是为\r\n
或者也可以这样写:
with open('data.csv', 'a', newline='')as f: # 将数据保存到文件中
writer = csv.writer(f)
writer.writerow([n, num, status, name, indication, subject])
3.元组的解包(解构)
- 解包就是将元组当中每一个元素赋值给一个变量
例如:
my_tuple = 10,20,30,40
a,b,c,d = my_tuple
a,b,c,d的值就分别是10,20,30,40
- 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量保持一,也可以在变量前加一个
*
,这个变量将会获取元组中所有剩余的元素
例如:
a,b,*c = [1,2,3,4,5,6,7]
a,b,c的值分别是1
,2
,[3, 4, 5, 6, 7]
4. and 和 or
- 当一个
or
中的所有值为真,则选择第一个值 - 当一个
and
中的所有值为真,则选择第二个值
5. 写成{}
比写dict()
运行效率更快
6. 占位符:_
_
除了用于占位符,它还可以在交互模式下,返回上一次的运行结果
7. 使用json.tools
快速格式化json
例如:
python -m json.tool demo.json
8. 让脚本报错后直接进入调试模式
通常我们在测试代码是,有时候会报错而导致直接退出,可以使用参数-i
,即可在脚本执行完毕后进入python shell
模式,就算你正常退出脚本也会自动进入到命令行模式
9. 在执行python自动执行一个脚本
首先我们需要新建一个用户环境目录,可以使用
python -c "import site;print(site.getusersitepackages())"
查看用户环境目录,然后使用mkdir -p
创建
然后在该目录下新建一个usercustomize.py
(必须是这个名字),然后里面写入脚本内容,
比如写入print('python start')
这样在每次执行python脚本是都会在最前面打印python start
10. 使用__import__
或__builtins__
进行导包
这一个知识点可以在ssti中使用进而进行远程命令执行,其定义为:
__import__(name[, globals[, locals[, fromlist[, level]]]])
例如:
__import__('os').popen('id').read()
既然__import__
是内建函数,那么必然存在于__builtins__
中,所以也可以
__builtins__.__dict__['__import__']('os').popen('id').read()
11. 使用exec执行
例如:
>>> with open('/opt/anaconda3/lib/python3.8/os.py') as f:
... exec(f.read())
...
>>> getcwd()
'/Users/yuaneuro'
>>> popen('whoami').read()
'yuaneuro\n'
>>>
12. 海象运算符
:=
可在表达式内部为变量赋值
使用海象运算符更适合用于传统的do/while 循环,
它在替换无限while循环中最有用:
while True:
p = input("Enter the password: ")
if p == "password":
break
使用海象表达式
while (p:=input('Enter the password:')) != 'password' :
continue
13. 重试机制
当我们遇到网络请求是,难免会遇见一些超时或其他不可控的情况导致程序退出,一般我都会采用异常捕获来进行重试,但是这样有时候会很麻烦而且影响代码的阅读性,这时我们就可使用一个第三方tenacity
来解决。
例如:
from tenacity import retry, wait_fixed
@retry(wait=wait_fixed(2))
def func():
print('asd')
raise Exception
if __name__ == '__main__':
func()
当运行报错时,就会每隔2秒重试一次,如果是无条件重试,可以直接写成@retry()
例如还有:
- 只重复7次:
@retry(stop=stop_after_attempt(7))
- 只重试10秒:
@retry(stop=stop_after_delay(10))
- 只出特定的报错才重试:
@retry(retry=retry_if_exception_type(exceptions.Timeout))
- 重试失败后,默认会抛出RetryError而不是根本原因,只需加一个参数
reraise=True
即可在出错时抛出原来的那个异常。
(记得导出相应的包)
14. 分隔符为\n
的时候可以直接用splitlines
进行分割
>>> str = "a\nb\n"
>>> str.split('\n')
['a', 'b', '']
>>> str.splitlines()
['a', 'b']
15. 流式读取超大文件
一般我们打开文件时都会用with open...
,但是如果读取一个很大的文件时,python会将文件内容一次性全部载入内存中,对内存消耗巨大,例如:
with open('big_file.txt') as f:
data = f.read()
- 当然其中的一个办法就是用生成器来逐行返回:
def read_file(filename):
with open('big_file.txt') as f:
yield f.readline()
- 或者是指定每次固定大小的内容进行读取,比如每次只读取8kb返回:
with open('big_file.txt') as f:
while True:
chunk = f.read(1024*8)
if not chunk:
break
yield chunk
16. 反转字符串或者列表
[::-1]
一看就懂,不解释了
17. 将print内容输出到文件
with open('log.txt', 'w') as f:
print('hello_world', file=f, flush=True)
18. else的几种用法
- 最简单的就是
if ... else...
- 然后是
for ... else ...
,这个我再第一个跳出双层循环中已经说了:没有被break的程序才会走else流程 try ... else ...
:不抛出异常,就可以走else
其实可以发现for ... else ...
和try ... else ...
是差不多的,只要代码正常走下去不被break,不抛出异常,就可以走else
参考文章:Python 黑魔法手册