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 黑魔法手册

最后修改:2022 年 01 月 25 日
如果觉得我的文章对你有用,请随意赞赏