note

让网页可以编辑:document.body.contentEditable=’true’; # F12在console控制台输入这个

不让复制,看这里,简单来说,按F12,点击齿轮形状进到设置里,Preferences–>(下拉到Debugger)Disable JavaScript选中,就禁用掉js了

​ 好像在linux中的shell和MongoDB中,使用的正则表达式都是用两个斜线//包起来的,如 /^a/ 以a开头的,跟python中有这一点点区别,不要双斜线(不一定有用的)

​ 特别注意:==在python中,所有模块中里的py文件里要是用到了相对路径,这个相对路径一定是文件相对运行的py文件的路径==,所以,调用一个相同的py代码,可能因为启动的py文件所在路径的差异,那个被调用的py文件中其它文件相对路径就要做调整,不然就会出现错误。

在ipython中输入==help()==,就会进到帮助界面,然后输入想要查看的命名,如getattr,就可以查看它的用法;或者直接help(getattr)

任何一个对象,比如aa,打印出来类似这种<module ‘builtins’ (built-in)>,都会有一个属性,aa.__dict__会得到一个字典,就可以看到其属性,就可以使用

python-cheatsheet:有类似python语法,常用库的小demo

命令行下载视频:conda activate base && you-get 视频链接 # 还有类似的项目

jupyter打开命令:在cmd里,输入 jupyter notebook

1、直接python执行语句

python -c "while True:import random;print(random.choice('|| __'), end='')"

2、python -m


00. 指定GPU使用哪张

  1. CUDA_VISIBLE_DEVICES=1 python main.py (这是在指定使用编号为1的GPU) OMP_NUM_THREADS=4 python main.py # 根据mmopenlab介绍,他们默认设为1的,可以根据自己的情况来看看,要不要变

  2. 执行程序前这么加前面的就好 CUDA_VISIBLE_DEVICES=’0,1,2,3’ python train.py (也可以这样指定编号)

  3. 在主程序代码里 import os os.environ[‘CUDA_VISIBLE_DEVICES’] = ‘0’

    ​ # 给’-1’的话,force torch.cuda.is_available() = False

  4. 或者: import torch.nn as nn model=nn.DataParallel(model,device_ids=[0,1,2]) # multi-GPU

  5. 也可以: import torch torch.cuda.set_device(0)

  6. 或者代码里指定device时:(”cuda:0”、”cuda:1”指定,直接给”cuda”默认就是用的0) device = “cuda:1” if torch.cuda.is_available() else “cpu”

01. 文件复制

import shutil
shutil.copy(oid_file,  new_path)   # 前面是文件名+它的地址,后面一个要复制的目录
shutil.move()  同理
shutil.copytree()  # 文件夹的复制,因为源码问题,目标文件夹不能存在

if os.path.exists('output/'):
    shutil.rmtree('output/')  # 删除文件夹
    os.makedirs('output/')

02. 计数

from collections import Counter
str = "abcbcaccbbad"
li = [2, 3, 43, 3, 45, 54, 33, 33, 1]
d = {'d': 3, 'f': 4, 'g': 3, 'h': 5}

# 获取元素个数,返回字典
print(dict(Counter(str)))
print(dict(Counter(li)))

# most_common(int) 按照元素出现的次数进行从高到低的排序,返回前int个元素的字典
print(Counter(str).most_common(2))  # 结果是list
print(dict(Counter(str).most_common(2)))  # 这就是把上面的结果包成了dict,跟Counter无关

03. 内容为字典的字符串转成字典

方法1
import ast
user = '{"name" : "john", "gender" : "male", "age": 28}'
user_dict = ast.literal_eval(user)

方法2通过json
import json
user = '{"name" : "john", "gender" : "male", "age": 28}'
user_dict = json.loads(user)           # 但是注意一定,将要成为字典的键和值,在字符串时必须是双引号,单引号不行(可以replace替换掉)

方法3eval()函数
user_dict = eval(user)   # 这是最简单的

04. sys|input输入

str = input(“请输入你的年龄”), 进来的是string,记得转int;

若给是enter回车,那么 str==”” 是成立的。给的空格的话,那么 str==’ ‘ 是成立的。

for line in sys.stdin.readlines():
    print(line.strip())  # 说是这自带一个换行符,,print也有一个,所以要去掉

# 然后可以将整个文件重定向输入,这根input是很不一样的
python my_test.py < 123.txt

​ 输入三个数,而不是循环:

print("Enter 3 coefficients of full quadratic equation: ")
a, b, c = list(map(float, input().split()))

调用外部程序:subprocess

调用外部程序的两种简单方式:

  1. import os os.system(“ffprobe demo.mp4”) # 这执行成功后会返回0 所以可以 if os.system(“where ffmpeg”) == 0 # 这样做判断 输出信息可以不要:( 2>&1 表示标准输出和标准错误都重定向)

    • linux:os.system(“where ffmpeg > /dev/null 2>&1”)
    • win:os.system(“where ffmpeg > nul 2>&1”) # win中 NUL表示空设备
  2. import subprocess ​process = subprocess.Popen([“nvidia-smi”, “-L”], stdout=subprocess.PIPE, stderr=subprocess.PIPE) ​stdout, stderr = process.communicate() # 这样会把运行的结果存起来

    • 这是在三维重建openMVG中看到的
    # 这是在openMVG中看到的
    print ("2. Compute features")
    # 计算特征:(matches_dir是前面的变量)
    pFeatures = subprocess.Popen( ["./ComputeFeatures.exe",  "-i", "sfm_data.json", "-o", matches_dir, "-m", "SIFT", "-f" , "1"] )  
    pFeatures.wait()
       
    print ("3. Compute matches")
    pMatches = subprocess.Popen( ["./ComputeMatches.exe",  "-i", "sfm_data.json", "-o", matches_dir, "-f", "1", "-n", "ANNL2"] )   
    pMatches.wait()
    

有一个别种方式的导包:

import os
os.system("dir")

__import__("os").system("dir")   # 两个效果是一样的,都是调用外部程序

05. tqdm|终端带颜色

import tqdm

for item in tqdm.tqdm(itemPrefs, desc=”寻找相近课程”)

from termcolor import colored
print(colored("你好", "green"))
print(123)  # 里面的源码可以看下,对颜色输出的处理

print也可以直接做到,这篇文章,termcolor内部应该就是用的这个原理。

06. ppt、word转txt文本

​ window

"""直接将ppt文件或word文档转成txt格式;
但是只能在window下使用,因为使用了win32com这个库,它是直接调用ppt、word底层来的,效果最好"""
pip install pypiwin32还是pywin32哦

import os
import win32com
from win32com.client import Dispatch

def win_ppt2txt(file_path):
    """文件的绝对路径"""
    assert file_path.endswith('ppt') or file_path.endswith('pptx')
    ppt_cl = win32com.client.Dispatch('PowerPoint.Application')
    ppt = ppt_cl.Presentations.Open(file_path, ReadOnly=1, Untitled=0, WithWindow=0)

    txt_save_path = os.path.splitext(file_path)[0] + ".txt"
    txt = open(txt_save_path, "w", encoding="utf-8")
    slide_count = ppt.Slides.Count
    for i in range(1, slide_count + 1):
        shape_count = ppt.Slides(i).Shapes.Count
        for j in range(1, shape_count + 1):
            if ppt.Slides(i).Shapes(j).HasTextFrame:
                s = ppt.Slides(i).Shapes(j).TextFrame.TextRange.Text
                txt.write(s)
    txt.close()
    ppt.close()
    ppt_cl.Quit()

def win_word2txt(file_path):
    """只能在window下使用;要文件的绝对路径"""
    assert file_path.endswith('doc') or file_path.endswith('docx')
    txt_save_path = os.path.splitext(file_path)[0] + ".txt"
    doc_cl = win32com.client.Dispatch('Word.Application')
    doc = doc_cl.Documents.Open(FileName=file_path, ReadOnly=1)
    temp_path = os.path.join(os.path.dirname(file_path), "temp123.txt")
    doc.SaveAs(temp_path, 2)
    doc.Close()

以下是各系统通用:不支持.doc .ppt 格式的文件

import os
from pptx import Presentation
from docx import Document

# file_path文件的绝对路径
def word2txt(file_path):
    assert file_path.endswith('docx')
    with open(file_path, "rb") as f:
        document = Document(f)

    txt_save_path = os.path.splitext(file_path)[0] + ".txt"
    with open(txt_save_path, 'w', encoding="utf-8") as f:
        for context in document.paragraphs:
            line = context.text
            f.write(f"{line}\n")

def ppt2txt(file_path):
    assert file_path.endswith('pptx')
    txt_save_path = os.path.splitext(file_path)[0] + ".txt"
    outfile = open(txt_save_path, "w", encoding="utf-8")
    pptx = Presentation(file_path)
    # 遍历ppt文件的所有幻灯片页
    for slide in pptx.slides:
        for shape in slide.shapes:
            if shape.has_text_frame:
                text_frame = shape.text_frame
                # 遍历文本框中的所有段落
                for paragraph in text_frame.paragraphs:
                    outfile.write(f"{paragraph.text}\n")
    outfile.close()

pdf下载

保存pdf其它所有网上的文件拿到url都能这样下载吧

import requests
url = r"http://disc.static.szse.cn/download/disc/disk03/finalpage/2022-03-05/f5e61a0a-3523-4603-83a0-7fb7dc3d97b3.PDF"   # 拿到pdf的url
result = requests.get(url, stream=True)

"方式一:(这是网上看到的形式)"
with open("123.pdf", "wb") as fp:
    for chunk in result.iter_content(chunk_size=10240):
        if chunk:
            fp.write(chunk)
# 两个效果是一样的,上面可能更保险一些吧
"方式二:这是前面记笔记的方式"  # 其它比如压缩包,图片,视频地址都可以这么来下载
with open("123.pdf", "wb") as fp:
    fp.write(result.content)  #r.content是返回文件的二进制形式

pdf转文本

​ 一般来说,先比如新建一个名为==pdf2txt.py==的文件,里面内容如下:

​ 环境:里面导包虽然用到的是pdfminer,但是不能直接pip install pdfminer,得到的版本不对;直接安装pdfplumber,就可以解决了——pip install pdfplumber

快速使用:(==建议只用来处理是扫描版的pdf,直接生成txt文本;扫描版转图片再ocr的话,用下面的方式==)

demo:python pdf2txt.py -o 123.txt -O ./jpg_files sample.pdf // 其它参数看下面

Ps:针对扫面版的pdf,得到的123.txt是一段乱码,sizeof也不大,基本上整个内容都是以图片的形式放进了jpg_files, 一样,好的图格式大抵都是.jpg,然后很多基本都是.bmp

以上一般是使用命令行来执行,如果要将其写进代码里,被其它方法调用的话:

import sys
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfdevice import PDFDevice, TagExtractor
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.cmapdb import CMapDB
from pdfminer.layout import LAParams
from pdfminer.image import ImageWriter

def main(argv):
    import getopt
    def usage():
        print(f'usage: {argv[0]} [-P password] [-o output] [-t text|html|xml|tag]'
              ' [-O output_dir] [-c encoding] [-s scale] [-R rotation]'
              ' [-Y normal|loose|exact] [-p pagenos] [-m maxpages]'
              ' [-S] [-C] [-n] [-A] [-V] [-M char_margin] [-L line_margin]'
              ' [-W word_margin] [-F boxes_flow] [-d] input.pdf ...')
        return 100

    try:
        (opts, args) = getopt.getopt(argv[1:], 'dP:o:t:O:c:s:R:Y:p:m:SCnAVM:W:L:F:')
    except getopt.GetoptError:
        return usage()
    if not args: return usage()
    # debug option
    debug = 0
    # input option
    password = b''
    pagenos = set()
    maxpages = 0
    # output option
    outfile = None
    outtype = None
    imagewriter = None
    rotation = 0
    stripcontrol = False
    layoutmode = 'normal'
    encoding = 'utf-8'
    pageno = 1
    scale = 1
    caching = True
    showpageno = True
    laparams = LAParams()
    for (k, v) in opts:
        if k == '-d':
            debug += 1
        elif k == '-P':
            password = v.encode('ascii')
        elif k == '-o':
            outfile = v
        elif k == '-t':
            outtype = v
        elif k == '-O':
            imagewriter = ImageWriter(v)
        elif k == '-c':
            encoding = v
        elif k == '-s':
            scale = float(v)
        elif k == '-R':
            rotation = int(v)
        elif k == '-Y':
            layoutmode = v
        elif k == '-p':
            pagenos.update(int(x) - 1 for x in v.split(','))
        elif k == '-m':
            maxpages = int(v)
        elif k == '-S':
            stripcontrol = True
        elif k == '-C':
            caching = False
        elif k == '-n':
            laparams = None
        elif k == '-A':
            laparams.all_texts = True
        elif k == '-V':
            laparams.detect_vertical = True
        elif k == '-M':
            laparams.char_margin = float(v)
        elif k == '-W':
            laparams.word_margin = float(v)
        elif k == '-L':
            laparams.line_margin = float(v)
        elif k == '-F':
            laparams.boxes_flow = float(v)
    #
    PDFDocument.debug = debug
    PDFParser.debug = debug
    CMapDB.debug = debug
    PDFPageInterpreter.debug = debug
    #
    rsrcmgr = PDFResourceManager(caching=caching)
    if not outtype:
        outtype = 'text'
        if outfile:
            if outfile.endswith('.htm') or outfile.endswith('.html'):
                outtype = 'html'
            elif outfile.endswith('.xml'):
                outtype = 'xml'
            elif outfile.endswith('.tag'):
                outtype = 'tag'
    if outfile:
        outfp = open(outfile, 'w', encoding=encoding)
    else:
        outfp = sys.stdout
    if outtype == 'text':
        device = TextConverter(rsrcmgr, outfp, laparams=laparams,
                               imagewriter=imagewriter)
    elif outtype == 'xml':
        device = XMLConverter(rsrcmgr, outfp, laparams=laparams,
                              imagewriter=imagewriter,
                              stripcontrol=stripcontrol)
    elif outtype == 'html':
        device = HTMLConverter(rsrcmgr, outfp, scale=scale,
                               layoutmode=layoutmode, laparams=laparams,
                               imagewriter=imagewriter, debug=debug)
    elif outtype == 'tag':
        device = TagExtractor(rsrcmgr, outfp)
    else:
        return usage()
    for fname in args:
        with open(fname, 'rb') as fp:
            interpreter = PDFPageInterpreter(rsrcmgr, device)
            for page in PDFPage.get_pages(fp, pagenos,
                                          maxpages=maxpages, password=password,
                                          caching=caching, check_extractable=True):
                page.rotate = (page.rotate + rotation) % 360
                interpreter.process_page(page)
    device.close()
    outfp.close()
    return
if __name__ == '__main__':
    sys.exit(main(sys.argv))

以下是一些参数说明:

"""
-P password : PDF password.
-o output : Output file name.
-t text|html|xml|tag : Output type. (default: automatically inferred from the output file name.)
-O output_dir : Output directory for extracted images.
    -c encoding : Output encoding. (default: utf-8)
-s scale : Output scale.
-R rotation : Rotates the page in degree.
-Y normal|loose|exact : Specifies the layout mode. (only for HTML output.)
-p pagenos : Processes certain pages only.
-m maxpages : Limits the number of maximum pages to process.
-S : Strips control characters.
-C : Disables resource caching.
-n : Disables layout analysis.
-A : Applies layout analysis for all texts including figures.
-V : Automatically detects vertical writing.
-M char_margin : Speficies the char margin.
-W word_margin : Speficies the word margin.
-L line_margin : Speficies the line margin.
-F boxes_flow : Speficies the box flow ratio.
-d : Turns on Debug output.
"""

pdf转jpg及ocr

pdf一些更多的处理,用得到的话,看这里

这个主要是针对扫描版的pdf转文字的话,第一步先转jpg,然后jpg使用自己改过的EasyOCR进行批量infer:

==pdf2jpg==:有两种方案


==批量OCR==:(主要用了自己修改后的EasyOCR进行批量infer)

07. 获取hash值及命令

"""
在window命令控制台中 certutil -hashfile  需要验证的文件路径  hash方法
certutil -hashfile window.iso MD5

certutil -hashfile yourfilename.ext SHA1

certutil -hashfile yourfilename.ext SHA256
"""

import hashlib
with open(r"F:\environment\iso\Windows.iso", "rb") as f:
    data = f.read()
    md5 = hashlib.md5(data).hexdigest()
    print(md5)
# md5 = hashlib.md5()
# SHA1 = hashlib.sha1()
# SHA256 = hashlib.sha256()

08. 图片|视频与base64互转

import io
import numpy as np
import cv2
import base64
from PIL import Image
import matplotlib.pyplot as plt
# 首先把图片转成base64字符串放进json保存
image_path = r"123.png"
with open(image_path, "rb") as f:
    data = f.read()
    img_base64 = base64.b64encode(data)
    img_str = str(img_base64, encoding="utf-8")   # 这是这个值就是一个字符串,可以放进json去存储起来
   
# 读取json,获取图片的字符串,再转换回来;可以直接展示,也可以存储起来
new_image = base64.b64decode(img_str)  # 这现在就是一个二进制文件
# 1、使用Image
img1 = Image.open(io.BytesIO(new_image))
img1.show()  # 或者 plt.imshow(new_image);plt.pause(5)  
img1.save("456.png")  # 可以这样保存
# 2、使用opencv
img2 = cv2.imdecode(np.array(bytearray(new_image), dtype='uint8'), cv2.IMREAD_UNCHANGED)
cv2.imshow("1", img2)
cv2.waitKey(500)
cv2.imwrite("789.png", img2)  # 也可以这样保存

# 或者这样直接存图
with open("new.png", "wb") as f:
    f.write(new_image)

视频也是类似:

import base64
from base64 import b64decode, b64encode
with open("./video.mp4", "rb") as fp:
    mp4 = fp.read()
# b64编码后还是byte类型,后面.decode()就是将其转为字符串,就可以和其它字符串拼接
res = base64.b64encode(mp4).decode()   

# 又将其写回为视频文件
new_video = b64decode(res)
with open("123.mp4", "wb") as fp:
    fp.write(new_video)

opencv读取的图像,一张张转格式并发往服务端:

import json
import base64

def trans(img_array): # 传进来的就是ret, frame = cap.read()中的frame
    h, w, c = img_array.shape
    img_encode = base64.b64encode(img_array)  # 转换为二进制
    image_info = dict(
        height=h,
        width=w,
        image=str(img_encode, encoding="utf-8")  # 要转成str才能转成json格式,且这里一定要指定编码方式,不然后续base64解码会报错
    )
    return json.dumps(image_info)

注意:base64变成bytes后,要转成str,不然json无法dumps,且转str时一定要指定编码方式,不然服务端拿到数据后通过base64转回去的时候会报错

服务端拿到这传过来的图像json数据后,这样处理:

from flask import Flask, request

@app.route("/predict", methods=["POST"])
def server():
    datas = request.data.decode()   # 网络出来的json数据
    datas = json.loads(datas)     # json包加载出来
    img_h = datas.get("height")
    img_w = datas.get("width")
    img_data = datas.get("image")  # 图片的二进制格式,通过base64编码

    img_data = base64.b64decode(img_data)   # 解码(client中一定要指定utf-8,不然这会报错)
    img_array = np.frombuffer(img_data, np.uint8)  # 注意这里numpy从buffer中拿数据的操作,工业摄像头的处理用也用到了
    # 下面这就是服务器拿到的BGR图像array了
    img = img_array.reshape((img_h, img_w, -1))  # 上面拿到的是一维的,要回到三维

一些编码:

普通字符串(在python中字符串默认使用unicode编码)

将中文转换为unicode
str = '你好'
uni = str.encode('unicode-escape').decode()
print(uni)
或直接打印
e = '\u6211\u559c\u6b22\u4f60'    # 带u的,这好像是转义字符
print(e)     # 这会直接打印出来汉子

09. 二维列表拉成一维

from itertools import chain
a = [[1, 2], [3, 4]]
temp = chain(*a)  # 结果是一个对象
list(temp)  

# 或者借用numpy
import numpy as np
res = np.asarray(a).flatten().tolist()

10. 用0在数字前填充

做制作数据时,一般都要将图片名称长度保持一致,在左边添加0,有两种比较好的方式:

关于数据通过format格式化,还可以对齐,要各种格式的表示,可以看python菜鸟教程

11. 不规则区域填充

temp_img = np.zeros(IMAGE_SIZE, dtype=np.uint8)  # 这只能给uint8
pts = np.asarray(key_area, dtype=np.int32)  # 这里要么是int32,要么就int,其它不行
# 把配置文件里画定区域内填充为1
cv2.fillPoly(temp_img, [pts], color=(1, 1, 1))
# cv2.fillPoly(temp_img, [np.array([[100, 100], [300, 100], [300, 700], [100, 700]])], color=(1, 1, 1))
result[cam_id][key_id] = temp_img

注意:这个pts里面的点,顺序一定是要对的,顺序是随意的话,画出来的图是不对的

12. 函数用时测试:timeit

time.time() 、time.perf_counter()、time.process_time()

import time
t0 = time.time()                 # 精度上相对没有那么高,而且受系统的影响,适合表示日期时间或者大程序程序的计时
c0 = time.perf_counter()         # 适合小一点的程序测试,会计算sleep()时间
p0 = time.process_time()         # 适合小一点的程序测试,不会计算sleep()时间
r = 0
for i in range(10000000):
    r += i
time.sleep(2)
print(r)
t1 = time.time()
c1 = time.perf_counter()
p1 = time.process_time()
spend1 = t1 - t0
spend2 = c1 - c0
spend3 = p1 - p0
print("time()方法用时:{}s".format(spend1))
print("perf_counter()用时:{}s".format(spend2))
print("process_time()用时:{}s".format(spend3))
import timeit
timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)  # 必须是个 str

IED内测某个用时
import timeit
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
a = np.random.randn(1000, 1000)

# 方法1:一定要记得加个globals=globals()参数
print(timeit.timeit("cosine_similarity(a)", number=100, globals=globals()))

# 方法2:把这些都封装到一个方法里,然后通过setup导入启动(小的测试用上面,大的测试封装成一个办法用下面)
def mytest(para):
    out = cosine_similarity(para)

if __name__ == '__main__':

    print(timeit.timeit("mytest(a)", setup="from __main__ import mytest, a", number=100))
    print(timeit.timeit("cosine_similarity(a)", setup="from __main__ import cosine_similarity, a", number=100))

其它的一些方法:

函数时间测试:

python -m cProfile  abc.py     # cProfile  测试abc.py里的函数用时
python -m cProfile  -s cumulative abc.py   # 按照时间排序,可以先s后面不跟,,可以看到有哪些可以排序的

或者直接使用timeit在命令行测试一小段代码的运行时间:

python -m timeit "'-'.join(str(n) for n in range(100))"

获取此刻的时间

from datetime import datetime
datetime.now().strftime("%Y-%m-%d %H:%M:%S")

import time
time.ctime()    # 结果是字符串,是带英文月份的结果,不是很直观,用上面的

Tips:

实参 含义
%A 星期的名称,如 Monday
%B 月份名,如 January
%m 用数字表示的月份( 01~12 )
%d 用数字表示月份中的一天( 01~31 )
%Y 四位的年份,如 2015
%y 两位的年份,如 15
%H 24 小时制的小时数( 00~23 )
%I 12 小时制的小时数( 01~12 )
%p am 或 pm
%M 分钟数( 00~59 )
%S 秒数( 00~61 )

获取时间戳:

import time
t = time.time()

print (t)                       #原始时间数据       1648812012.4263625
print (int(t))                  #秒级时间戳,10位   1648812012
print (int(round(t * 1000)))    #毫秒级时间戳,13位 1648812012426
print (int(round(t * 1000000))) #微秒级时间戳,16位 1648812012426362

13. glob

​ glob模块是python自己带的一个文件操作模块,可以查找符合自己需求的的文件,并且支持通配符操作,主要包括以下三种匹配模式:

  1. *代表0个或多个字符。
  2. **匹配所有文件,包括目录,子目录和子目录里面的文件。
  3. ?代表一个字符。
  4. []匹配指定范围内的字符,如[0-9]匹配数字。
  5. [!] 匹配不在指定范围内的字符。
import glob
glob.glob("./python[0-9].py")   # 当前路径文件下以 .python开头并且有一个数字的所有py文件
glob.glob(labelme_path + "/*.json")  # labelme_path路径下所有的json文件

iglob()方法不同于glob()方法,其返回的是一个迭代器(类似于yield)

glob.iglob()

14. argparse的使用

简单的直接使用内置的添加参数:

import sys
# sys.argv[0]是当前脚本的名字,
args = sys.argv[1:]     # args是一个列表,所有后面输入的参数

-v --verbosity 就是短参数和长参数,跟-h --help的作用是一样的(还有一些更多的参数用法,这里

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("img_path",help="这种前面没有--的,后面可以直接跟参数,而不用显式指定这个参数名,像下面带了--的都要显式的指定参数名")
parser.add_argument("-v", "--verbosity",required=True,help="添加输出 verbosity")
 # 还可以指定参数类型 type=str 这种
args = parser.parse_args()

# 其它地方要获取到传入的参数就是这 .参数名去拿
if args.verbosity:
    print("打开 verbosity:{}".format(args.verbosity))

那么这种使用的时候就是一样的,后面必须要有参数值:

  1. python file.py -v hello
  2. python file.py - -verbosity hello

action="store_true" 使用的解读:

parser.add_argument("-v", "--verbosity", action="store_true")
args = parser.parse_args()
if args.verbosity:
    print("打开 verbosity")
    
# 另外还可以给把默认值给为None,这样传参时直接判,没有就不进去
parser.add_argument("--text_prompt", type=str, default=None, help='use text prompt eg: "a dog"')

加了 action=”store_true”后,后面就可以不给具体参数值,默认是False, 如果 -v 就给它变成了true,就可以:

  1. python file.py -v
  2. python file.py - -verbosity

这样就跟一些pip -h获取帮助,只是给-h,后面不给参数值一样了

以及可选的情况:

parser.add_argument(
        '-t', '--type', type=str, default='detect', choices=['detect', 'cls', 'seg'], help='determines the model is detection/classification')

另外一种快速获取外部参数输入的方法:

import sys
print(sys.argv[1:])    # 这会打印一个列表,里面是所有传进来的参数
sys.argv[0]   # 得到的就是这个py文件的全名称- 1.py

同类型的还有一个google开源的项目python-fire,import fire,看了一下,这个简单的demo。对于比较简单自用的一些函数,可以尝试用这个,十分便捷,比argparse方便。

15. os.walk:

path = r"C:\动态壁纸\1080P"
for root, dirs, files in os.walk(path):
    # path文件夹下所有文件(包括子文件夹下的文件)的绝对路径
    for name in files:
        print(os.path.join(root, name))
        
    # # 这里得到的都是所有递归目录的路径,所有文件的上一级目录
    # for name in dirs:
    #     print(os.path.join(root, name))

16. assert断言

assert args.output_video_name.endswith(".avi"), "the format must be '.avi'"   # 要是断言失败,错误信息就会把后面这句话打出来

17. Path路径的组合

一般常用的是os模块,使用的是:os.path.join(a_path, “123”, “aa”),这样的形式,但是可能linux和windows下斜杠的问题,可以推荐一种形式:

from pathlib import Path
path = "一个给定的路径"
path = Path(path).joinpath(*("456", "aaa", "789"))  # 这就是把后面几个组合起来
Path(path).mkdir(parents=True, exist_ok=True)   # 固定搭配使用吧

pathlib用于导包

​ 比如我写好了一个项目,项目导包的路径是ok的,但如果此刻把这个项目放进另一个项目作为子项目,导包的路径很大概率是有问题的,解决思路来源于yolov5的代码。简单来说,就是在找不到路径的代码里写上这么几行:(具体情况可能有变)

import sys
import os
from pathlib import Path
    
FILE = Path(__file__).resolve()
ROOT = FILE.parents[0]  # 0 是当前文件所在路径,1 的话就是上一级路径
if str(ROOT) not in sys.path:
    sys.path.append(str(ROOT))  # add ROOT to PATH
# 最后一句不一定要,前面的有就ok了。
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative

# 或者这么使用(把这写成函数去调用)
current_path = Path.cwd()    # 当前py的路径
logs_dir = current_path.parent / "logs"   # 当前py路径的上一级路径下的 logs 目录
logs_dir.mkdir(parents=True, exist_ok=True)
log_path = str(logs_dir / "123.log")  #  注意把类型转为str

18. python调用动态链接库

python使用的话:

import ctypes
dll_path = r"F:\VS_project\Project2\x64\Debug\Project2.dll"    # 因为现在系统多为x64,得要x64的动态链接库

pdll_1 = ctypes.WinDLL(dll_path)
pdll1_2 = ctypes.cdll.LoadLibrary(dll_path)  # 暂时目前来说,两个效果是一样的

value = pdll.sum(5, 6)   # 然后就可以调用里面的函数了

​ 以上是参照此处,按照上来的教程来,可能会出现OSError: [WinError 193] %1 不是有效的 Win32 应用程序。然后是按照这来解决的。

19. pylint代码规范检查

使用 pylint 来检查代码的规范,安装 pip install pylint

使用:命令行里,使用 pylint 123.py 它就会检查代码规范

格式如下所示: 模块名:行号:列号: 消息类型 消息

消息类型有以下几种:

  1. C - 惯例:违反了Python编程惯例(PEP 8)的代码。
  2. R - 重构:写得比较糟糕需要重构的代码。
  3. W - 警告:代码中存在的不影响代码运行的问题。
  4. E - 错误:代码中存在的影响代码运行的错误。
  5. F - 致命错误:导致Pylint无法继续运行的错误。

Pylint命令的常用参数:

  1. --disable=<msg ids>-d <msg ids>:禁用指定类型的消息。
  2. --errors-only-E:只显示错误。
  3. --rcfile=<file>:指定配置文件。
  4. --list-msgs:列出Pylint的消息清单。
  5. --generate-rcfile:生成配置文件的样例。
  6. --reports=<y_or_n>-r <y_or_n>:是否生成检查报告。

另外还看一个也是平写检查的包:pyenchant

这个包为Enchant拼写检查库提供了一组Python语言绑定(暂时还没用过)

20. ipython中的使用

ipython可以使用tab提示变量名?    就是在变量名前或后加个?,,可以得到这个变量的相关信息俗称内省
两个??可能还可以看到源码
np.*load*  就可以得到numpy中顶级命名空间里含有load的函数

# 这是魔术方法
a = np.random.randn(100, 100)
%time np.dot(a, a.T)    #只执行一次获取时间
%timeit np.dot(a, a.T)    # 通过多轮测试获取它的用时
%timeit -n50 np.dot(a, a.T)    # 也可以会指定测试50轮

输出   !cmd  就切换到cmd去了

21. try…except…else

这是try-except-else模块,else可以不要,但是有会更加简洁,告诉人们try成功执行后再执行的代码。

import traceback  #异常处理的包
try:
    boxes = np.split(_boxes, len(_boxes) // 5) 
except Exception as e:   #这里也可以exccept:  后面给pass,就是什么都不要报告,直接跳过
    print(e)  # 打印的错误信息比较少
    # 这是将所有的错误信息打印出来;全是红的,系统报错那种,但是不影响程序的继续执行
    traceback.print_exc()
    traceback.print_exc(file = open("tb.txt", "w+"))  # 还可以这样将其写进tb.txt文件中
    traceback_info = traceback.format_exc()  # 这就是拿到报错的所有详细字符串,然后可以用logging模块去做操作
    print(12345)  # 这后面还可以执行代码
else:   
    print("try成功后会执行的代码!")

tips:以上获取异常相关的数据都是通过==sys.exc_info()==函数得到的。

​ 还有 try…except…finally:无论前面怎么执行,后面的finally都会被执行。


同样还有 for…else,简单来说:

for循环是被break中断的,就不会执行else中的语句,如果是循环完整了,就会执行else

for i in range(10):
    print(i)
    if i == 3:
        break
else:
    print("循环完整就会执行else语句")  # 这不会被执行

除此, while…else 跟for else是一样的使用。

22. python小知识.txt

print()在输出完后会自动换行,如不要,则在内容后输入 ,end=”” 即print(“你好不”,end=””),那么输出的内容就是你好不,且不换行 print(“张三”,”你好”,sep=”???”),打印的结果就是”张三???你好”

1、"""split()"""    分割(这里是将对空格的处理)
a = "000001.jpg    95  71 226 313"   # 想把a中的数据拿出来成为一个列表
print(a.split(" "))  # 若是选择以空格来分割,因为其中的空格不均匀,返回的列表中也会有空元素
# 就接下来两种方法
b = a.split(" ") 
print(list(filter(bool, b))) # (1)返回一个迭代器,不为空的值
print(a.split())  # (2)这俩效果是一样的;;所以建议直接a.split()

2、x = None
print(bool())  # False
print(bool(x)) # False
print(bool("fjd")) # True

3、"""count()"""      个数的统计
s="hello world"
print(s.count("l")) # 则是代表输出l的个数吗,为3个

4、"""join()   replace()"""   字符间加入其它符号     替代
s = "hello world"
print("@".join(s))  # 表示将s中的每个字符都用@连接起来,这个@可换
print("#".join("4653"))  # 结果是4#6#5#3,
# (在反转字符串时,可以将字符串转成列表、再反序,这时候每个字母间有逗号,可以选择这个join,前面就空白不填,就将其放在一起了),如下:
a = list(s)  # 字符串变列表
print(a[: :-1])    # 反转了,但成了列表,第一个冒号全切,第二个冒号后面代表步长
print("".join(a[::-1]))    # 反转了,变回了str (就是反转字符串)

5、""".index()"""    用于获取具体的str的索引
s="hello world"    # 也可以是列表
print(a.index('e'))    # 从左往右找到第一个e的索引;index里面还可以跟第二个参数(int),那代表从第int个索引开始往右查找)

6、"""dir()"""   获取模块中的所有变量名(包括自己定义的)

7、"""hasattr()"""    用于判断对象是否包含对应的属性(存在返回True,反之则False)
if hasattr(self,"bias"):   这是写在类里面的
    z += self.bias

11、"""getattr(a,"name","default")"""     # 判断a中是否有"name"这个属性,有就返回"name",没有就返回"default"; 也可以不给第三个参数,没有就直接报错
这应该是用在a是一个类的时候

12.扩展解包赋值(一个里面最多一个星号)
*a,b,c="你好吗?"
print(a,b,c)
结果就是["你","好"] 吗 ?    (星号是可以换位置的)

13、了解  __slots__ 
__slots__ = ("name", "age")    # 这放在类下第一行,__init__之前,就是代表限定这个类只能绑定“name”“age”属性

14、@abstractmethod    # 抽象类,要导包的,具体看网页面向对象进阶

15 、
message = input("tell me what you want:")
print(message)  #这样用户就可以输入数据了,而且上面的提示信息不会算到message中

16 、from random import choice
choice([1, 2, 3, 4])   #从这里面随机选出一个值

17、
x = 2.33
#四舍五入
print(round(x))
#向上取整
print(math.ceil(x))
#向下取整
print(math.floor(x))
#在numpy和pytorch中函数用法一模一样

写在这里,留作纪念吧:

起名字只能用字母(区分大小写)、数字、下划线,且不能数字打头

"\"是转义字符,在想打印的一些特殊符号前加上,会直接打印那些符号
\a  响一声
\b  退格(即覆盖掉上一个字符)
\f  换页(在打印时)
\t  八个空格
\n 长行内容从那里换行
\r 返回到本行的首行,例如print(“hi,\python”),会输出python

Raw字符串(字符串前加r,抑制转义):表示原始字符串,看到字符串是什么就是什么,所有字符串都不转义,
例如:a=r“\\”  print(a)  结果就是\\
  常加在地址、链接前,以确保要的就只是字符串文本

二进制是0b开头的,8进制0o开头,16进制0x开头(是零)
函数进制间的转换:
转为二进制:bin()
转为八进制:oct()
转为十六进制:hex()
转为十进制:int("要转换的数值",要转换的数值的进制)
注意不同进制间转换需要用十进制作为中间人,就是函数的嵌套

字符串需要用引号(无论单双);也可以用三个引号(无论单双),这个可以换行,前者不行
且可用于注释内容,也可换行,,单行注释可以在开头加#

a=5
b=3
print("5+3={1}".format(a+b),45,7,56)特别注意函数前是“.”  (这是字符串格式化)
结果是5+3=45,(那个“1”代表后面函数里的多个参数的顺序编号,从零开始数)
注意前面可以同时打印几个值,用“,”隔开,
如:print("5+3={0},5-3={1}".format(a+b,a-b))   
   注:(前面花括号里是可以放提示内容的,如  姓名,这前面无论中英文都不需要引号;后面format的内容,姓名="Ella",就是说赋值的内容,是中文或是英文字符串都需要加引号)

print(s.replace("d","t")),则是表示用t代替d
#这里记住字符串是无法修改的,有时候确实要改也要是这样s = s.replace('d', 't')重新赋值

for i in range(5, 0, -1):   #这是倒着生成5、4、3、2、1
    print(i)


==与is的区别
==是判断数值是否相等,is是判断地址是否相等
a=256,b=1256
print(a==b),结果为True ;print(a is b),结果也为True
c=257,b=257 (-5~256之间的数字放在了小整数对象池里面了,故上面的地址会相等,而下面的之外地址却不会相等)
print(a==b),结果为True;print(a is b),结果为False

23. COCO的可视化

​ 可以对coco数据集分割进行一个可视化,特别是人体关键点检测的一个可视化,参看这里,还有很多其它的姿态估计的关键点数据集可视化的代码demo。还可以参看这里。但更好的方式,是用SAM-Tool数据自动标注中的cocoviewer.py,配合它的README看使用。

​ pycocotools库来展示mask,在对于有同心圆这种是无法展示的,会把中间的空洞也画上mask,然后我改了它的实现代码,用的cv2.fillPoly和np.logical_xor逻辑亦或来实现的,可看SAM-Tool的convert_ann_to_mask函数,里面还有原来pycocotools实现的方式。此外还有cocoviewer.py,里面利用PIL库来实现的,不但可以处理coco中seg数据为轮廓点坐标,还可以处理是“RLE”格式的分割标注,可看它的draw_mask函数。

import os
from pycocotools.coco import COCO
from PIL import Image, ImageDraw
import matplotlib.pyplot as plt


# 可以看看这不同标注文件之间的区别(应该都是官网可下的)
# val_annotation_file = "./annotations/instances_val2017.json"
val_annotation_file = "./annotations/person_keypoints_val2017.json"
val_img_file = './val2017'

coco = COCO(annotation_file=val_annotation_file)
coco_classes = {v["id"]: v["name"] for k, v in coco.cats.items()}
idx = list(sorted(coco.imgs.keys()))

plt.figure(figsize=(10, 6))
for i in range(len(idx)):
    img_id = idx[i]  # 排序后最小的图片id为139 ,即img_id=139(这个注释针对person_keypoints_val2017.json)
    # 获取图片路径名
    ann_idx = coco.getAnnIds(imgIds=img_id)
    objects = coco.loadAnns(ann_idx)

    # 如果使用的注释文件是person_keypoints_val2017.json,且图片里没人的话,这个结果就是空的
    if not objects:
        continue

    path = coco.loadImgs(img_id)[0]["file_name"]
    img = Image.open(os.path.join(val_img_file, path))
    # import skimage.io as io   # 这种方法读图片也是一样的
    # img = io.imread(os.path.join(val_img_file, path))

    # 这是就把类别画上去,同时画上矩形框,影响观看的话就可以先注释掉
    draw = ImageDraw.Draw(img)
    for bbox in objects:
        x, y, w, h = bbox["bbox"]
        x1, y1, x2, y2 = x, y, int(x + w), int(y + h)
        draw.rectangle((x1, y1, x2, y2))
        draw.text((x1, y1), coco_classes[bbox["category_id"]])

    plt.clf()
    plt.axis('off')
    plt.imshow(img)
    # 核心是这行,把keypoint显示出来,如果是instances_val2017.json,就是分割显示;如果是person_keypoints_val2017.json,还会把谷歌关键点显示出来
    coco.showAnns(objects)
    plt.pause(1)

24. python加载.mat

数据如果被保存为.mat的格式,用python加载就是:

from scipy.io import loadmat
result = loadmat(path)

成功加载得到的结果就是一个字典。

25. 打包成exe

打包用:pyinstaller,好用,更多看这里

一般步骤:

  1. 记得要新建一个虚拟环境,尽可能减少包大小,只要当前程序要的库就好了。
  2. 安装:pip install pyinstaller
  3. 打包:pyinstaller -F -w main.py # 参数含义去看上面链接

26. 计算两根直线间夹角

​ 注意:我之前一般用 np.arctan(一条直线的斜率) * 180 / np.pi 的方式来计算,但计算斜率时,如果是90°,斜率是算不出来的,因为算斜率时被除数为0了,就要使用np.arctan2(dy1, dx1) * 180 / np.pi去算

import math     # 也可以用numpy

def two_line_angle(first_line_pts, second_line_pts):
    """
        计算两根直线的夹角
    :param one_line_pts: 第一条直线的两个点 [x1, y1, x2, y2]
    :param two_line_pts: 第二条直线的两个点 [x1, y1, x2, y2]
    :return: 返回两根直线的夹角,范围[0, 180]
    """
    dx1 = first_line_pts[2] - first_line_pts[0]
    dy1 = first_line_pts[3] - first_line_pts[1]
    dx2 = second_line_pts[2] - second_line_pts[0]
    dy2 = second_line_pts[3] - second_line_pts[1]

    
    # angle1 = math.atan2(dy1, dx1)
    angle1 = np.arctan2(dy1, dx1)
    angle1 = int(angle1 * 180 / math.pi)

    # angle2 = math.atan2(dy2, dx2)  # 用numpy是一样的
    angle2 = np.arctan2(dy2, dx2)
    print(angle2)
    print(np.arctan(dy2/dx2))  # 当dx2不为0的时候,angle2的结果和这是一样的,是角度的弧度值
    
    angle2 = int(angle2 * 180 / math.pi)  # 可以考虑不转成int
    if angle1 * angle2 >= 0:
        insideAngle = abs(angle1 - angle2)
    else:
        insideAngle = abs(angle1) + abs(angle2)
        if insideAngle > 180:
            insideAngle = 360 - insideAngle
    insideAngle = insideAngle % 180

    return insideAngle
if __name__ == '__main__':
    point_one = (0, 0, 1, 1)
    point_two = (0, 0, 1, 0)
    angle = two_line_angle(point_one, point_two)
    print(angle)

27. 得到随机的颜色

pip install distinctipy

from distinctipy import distinctipy

colors = distinctipy.get_colors(5)  # 得到5个颜色,[(0.5, 0.5, 0.1), (0.0, 1.0, 0.0),...]
colors = [tuple([int(255 * c) for c in color]) for color in colors]  # 就是 0-255的值了

28. 提取图像目标分割的部分

使用分割模型得到目标的轮廓后,将其提取出来,下面的代码是以yolov5的分割结果为例(伪代码)

import cv2
import numpy as np

image = cv2.imread("目标图片")
# 分割模型
segments = model.infer(image)
target_seg = segments[0]       # 假设第一个目标是我们要的,

# target_seg 的shape:(n, 2), 如果是yolov5的结果,它的类型就是ndarry,且值都在[0, 1]
# 把坐标还原回去
target_seg = target_seg * np.array(image.shape[:-1][::-1])  # 要乘(w, h)
contour = np.int(target_seg)  # 转成整型

# 在一个纯黑画布上把轮廓画出来,做一个mask
black_canvas = np.zeros_like(image)
cv2.drawContours(black_canvas, [contour], 0, color=(255, 255, 255), thickness=-1)  # 填充
black_canvas = cv2.cvtColor(black_canvas, cv2.COLOR_BGR2GRAY)  # mask必须是单通道的

# 位运算实现抠图
result = cv2.bitwise_and(image, image, mask=black_canvas)
cv2.imshow("result", result)
cv2.waitKey(0)
# 还可以找到轮廓的外接正矩形,直接只要目标区域
x, y, w, h = cv2.boundingRect(contour)
img = result[y: y + h, x: x + w, ...]  # 是 (h, w, c),注意顺序

29. 编译成pyc、.so库调用

将该函数py文件,放在待编译项目的一级,然后执行就好了,那么启动就是python 对应.pyc文件

把所有的py文件编译成pyc文件(编译生成的字节码),可选择生成新的工程目录,也可以选择删除源文件,仅保留pyc文件用于部署简单的加密,主要是用的compileall模块。

优点:

import datetime
from pathlib import Path
import os
import shutil
import compileall
 
def package(root_path="./test_project/",reserve_one=False):
    """
    编译根目录下的包括子目录里的所有py文件成pyc文件到新的文件夹下
    如果只保留一份文件,请将需编译的目录备份,因为本程序会清空该源文件夹
    :param root_path: 需编译的目录
    :param reserve_one: 是否只保留一个目录
    :return:
    """
    root = Path(root_path)
 
    # 先删除根目录下的pyc文件和__pycache__文件夹
    for src_file in root.rglob("*.pyc"):
        os.remove(src_file)
    for src_file in root.rglob("__pycache__"):
        os.rmdir(src_file)
 
    current_day = datetime.date.today()  # 当前日期
    edition = "1.0"  # 设置版本号
 
    dest = Path(root.parent / f"{root.name}_{edition}.{'001'}_beta_{current_day}")  # 目标文件夹名称
 
    if os.path.exists(dest):
        shutil.rmtree(dest)
 
    shutil.copytree(root, dest)
 
	# 还能加参数,maxlevels: 递归编译的层数, rx: 一个正则表达式,排除掉不想要的目录等等
    compileall.compile_dir(root, force=True)  # 将项目下的py都编译成pyc文件
 
    for src_file in root.glob("**/*.pyc"):  # 遍历所有pyc文件
        relative_path = src_file.relative_to(root)  # pyc文件对应模块文件夹名称
        dest_folder = dest / str(relative_path.parent.parent)  # 在目标文件夹下创建同名模块文件夹
        os.makedirs(dest_folder, exist_ok=True)
        dest_file = dest_folder / (src_file.stem.rsplit(".", 1)[0] + src_file.suffix)  # 创建同名文件
        print(f"install {relative_path}")
        shutil.copyfile(src_file, dest_file)  # 将pyc文件复制到同名文件
 
    # 清除源py文件
    for src_file in dest.rglob("*.py"):
        os.remove(src_file)
 
    # 清除源目录文件
    if reserve_one:
        if os.path.exists(root):
            shutil.rmtree(root)
        dest.rename(root)
 
 
if __name__ == '__main__':
    package(root_path="./SDG/",reserve_one=False)  # 这会保留源码
 
    # 会清空源文件夹,记得备份,适合上线部署,删除源代码,防止泄露
    # package(root_path="./test_project/",reserve_one=True)

还可以把python源码编译成.so文件,直接进行调用,只暴露接口,链接放这里,后面来研究后写示例。

还可以编译成pyd,没试过,感觉不是很舒服,放这里吧。

然后这里pycdc这个项目可以将pyc反汇编回可读的源码,有需要的时候可以试试看。

30. 监控cpu、gpu

​ 下面的代码获取到监控数据,然后写到influxdb时序数据库,再用grafana画出来就有一个可视化的展示(两个合起来使用的一个教程)。(或许可视化还可以用这个Kibana

from timeloop import Timeloop
from datetime import timedelta
import psutil   # 用来看cpu数据
import pynvml   # 用来看gpu数据

TL = Timeloop()

class Monitor():
    def __init__(self, sname):
        # 初始化一些参数
        self.M = 1024 * 1024
        self.G = self.M * 1024
        self.precision = 3
        self.server_name = sname  # 服务器名称
        pynvml.nvmlInit()
        self.handle = pynvml.nvmlDeviceGetHandleByIndex(0)

    def get_CPU_info(self):
        cpu_usage = psutil.cpu_percent(1)   # 这里得到的是百分比 0 ≤ cpu ≤ 100
        return round(cpu_usage, self.precision)

    def get_GPU_info(self):
        meminfo = pynvml.nvmlDeviceGetMemoryInfo(self.handle)
        gpu_total = round(meminfo.total / self.G, self.precision)       # 单位 GB
        gpu_used = round(meminfo.used / self.G, self.precision)         # 单位 GB
        gpu_free = round(meminfo.free / self.G, self.precision)         # 单位 GB
        gpu_usage = round(100*gpu_used / gpu_total, self.precision)     # 这里得到的是百分比 0 ≤ usage ≤ 100
        return gpu_total, gpu_used, gpu_free, gpu_usage

    def get_Mem_info(self):
        mem = psutil.virtual_memory()
        mem_used = round(mem.used / self.G, self.precision)             # 单位 GB
        mem_free = round(mem.free / self.G, self.precision)             # 单位 GB
        mem_buffers = round(mem.buffers / self.G, self.precision)       # 单位 GB
        mem_cached = round(mem.cached / self.G, self.precision)         # 单位 GB
        return mem_used, mem_free, mem_buffers, mem_cached

    def get_Disk_info(self):
        disk_usage = psutil.disk_usage('/')
        disk_total = round(disk_usage.total / self.G, self.precision)   # 单位 GB
        disk_used = round(disk_usage.used / self.G, self.precision)     # 单位 GB
        disk_free = round(disk_usage.free / self.G, self.precision)     # 单位 GB
        disk_usage = round(100*disk_used / disk_total, self.precision)  # 这里得到的是百分比 0 ≤ usage ≤ 100
        """
        read_count 读IO数
        write_count 写IO数
        read_bytes 读IO字节数
        write_bytes 写IO字节数
        read_time 磁盘读时间 ms
        write_time 磁盘写时间 ms
        # 下面是具体数据
        disk_io = psutil.disk_io_counters()
        disk_io_read_count = round(disk_io.read_count, self.precision)
        disk_io_write_count = round(disk_io.write_count, self.precision)
        disk_io_read_bytes = round(disk_io.read_bytes, self.precision)
        disk_io_write_bytes = round(disk_io.write_bytes, self.precision)
        disk_io_read_time = round(disk_io.read_time, self.precision)
        disk_io_write_time = round(disk_io.write_time, self.precision)
        """
        return disk_total, disk_used, disk_free, disk_usage


    def get_Network_info(self):
        network = psutil.net_io_counters()
        network_sent = round(network[0] / self.G, self.precision)
        network_recv = round(network[1] / self.G, self.precision)
        return network_sent, network_recv
        
    def run(self):
        cpu_usage = self.get_CPU_info()
        disk_total, disk_used, disk_free, disk_usage = self.get_Disk_info()
        gpu_total, gpu_used, gpu_free, gpu_usage = self.get_GPU_info()
        mem_used, mem_free, mem_buffers, mem_cached = self.get_Mem_info()
        network_sent, network_recv = self.get_Network_info()
        print("服务器名称:{}\n当前CPU使用率:{}\n当前硬盘使用率:{}\n当前GPU使用率:{}\n当前内存使用:{}G\n当前网络发送{}G,接收{}G\n"
        .format(self.server_name, cpu_usage, disk_usage, gpu_usage, mem_used, network_sent, network_recv))

@TL.job(interval=timedelta(seconds=5))
def loop():
    Monitor('2080Ti').run()

if __name__ == '__main__':
    try:
        TL.start(block=True)
    except Exception as e:
        print(str(e))
    finally:
        pynvml.nvmlShutdown()
        TL.stop()

31. Profile剖析代码性能

cProfile模块

example01.py

import cProfile
def is_prime(num):
    for factor in range(2, int(num ** 0.5) + 1):
        if num % factor == 0:
            return False
    return True

class PrimeIter:
    def __init__(self, total):
        self.counter = 0
        self.current = 1
        self.total = total
    def __iter__(self):
        return self
    def __next__(self):
        if self.counter < self.total:
            self.current += 1
            while not is_prime(self.current):
                self.current += 1
            self.counter += 1
            return self.current
        raise StopIteration()  
        
cProfile.run('list(PrimeIter(10000))')

执行结果:

   114734 function calls in 0.573 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.006    0.006    0.573    0.573 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 example.py:14(__init__)
        1    0.000    0.000    0.000    0.000 example.py:19(__iter__)
    10001    0.086    0.000    0.567    0.000 example.py:22(__next__)
   104728    0.481    0.000    0.481    0.000 example.py:5(is_prime)
        1    0.000    0.000    0.573    0.573 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

line_profiler(用这)

安装line_profiler第三方库:pip install line_profiler

给需要剖析时间性能的函数加上一个profile装饰器,这个函数每行代码的执行次数和时间都会被剖析。

example02.py # 下面就是里面的全部代码

@profile
def is_prime(num):
    for factor in range(2, int(num ** 0.5) + 1):
        if num % factor == 0:
            return False
    return True

class PrimeIter:
    def __init__(self, total):
        self.counter = 0
        self.current = 1
        self.total = total
    def __iter__(self):
        return self
    def __next__(self):
        if self.counter < self.total:
            self.current += 1
            while not is_prime(self.current):
                self.current += 1
            self.counter += 1
            return self.current
        raise StopIteration()

list(PrimeIter(1000))

使用line_profiler第三方库:kernprof -lv example02.py # 就会得到如下结果

Wrote profile results to example02.py.lprof
Timer unit: 1e-06 s

Total time: 0.089513 s
File: example02.py
Function: is_prime at line 1

 #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
 1                                           @profile
 2                                           def is_prime(num):
 3     86624      43305.0      0.5     48.4      for factor in range(2, int(num ** 0.5) + 1):
 4     85624      42814.0      0.5     47.8          if num % factor == 0:
 5      6918       3008.0      0.4      3.4              return False
 6      1000        386.0      0.4      0.4      return True

memory_profiler

安装:pip install memory_profiler

给需要剖析内存性能的函数加上一个profile装饰器,这个函数每行代码的内存使用情况都会被剖析。

example03.py

@profile
def eat_memory():
    items = []
    for _ in range(1000000):
        items.append(object())
    return items
eat_memory()

使用memory_profiler第三方库:python -m memory_profiler example03.py

Filename: example03.py

Line #    Mem usage    Increment   Line Contents
================================================
     1   38.672 MiB   38.672 MiB   @profile
     2                             def eat_memory():
     3   38.672 MiB    0.000 MiB       items = []
     4   68.727 MiB    0.000 MiB       for _ in range(1000000):
     5   68.727 MiB    1.797 MiB           items.append(object())
     6   68.727 MiB    0.000 MiB       return items

python鼓励:

EAFP优于LBYL。

EAFP - Easier to Ask Forgiveness than Permission.

LBYL - Look Before You Leap.

参考

其它未写好: