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
即可在出错时抛出原来的那个异常。
(记得导出相应的包)
当使用requests时,可以用下面方式实现超时重传:
import requests
s = requests.Session()
s.mount('http://', HTTPAdapter(max_retries=10)) # 代表超时重试的次数
s.mount('https://', HTTPAdapter(max_retries=10))
s.get('https://yuaneu.ro/', timeout=5)
上面这个就是设置超时时间是5秒,如果超时10次就会报错
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
19. 获取网址ip
import socket
domain = 'yuaneu.ro'
addr = socket.getaddrinfo(domain, None)
print(ip := addr[0][4][0])
缩减一下
__import__('socket').getaddrinfo('yuaneu.ro', None)[0][4][0]
20. python正则提取中文
re.compile(r'[\u4e00-\u9fa5]')
21. 使用telnet测试ip开放端口
import telnetlib
try:
telnetlib.Telnet('192.168.160.201', 80, timeout=10)
print('success')
except:
print('fail')
21. 定时发送
import threading
import time
def demo():
...
print(time.time())
t = threading.Timer(5, demo) # Timer(定时器) 每隔5秒运行一次demo()
t.start()
if __name__ == '__main__':
demo()
参考文章:Python 黑魔法手册