西区代码小仓库 - python
type: channel
link: https://www.lisper517.top/category/python/
description: python拯救众生
items: 《深度学习入门 基于Python的理论与实现》-斋藤康毅（笔记）
items: 按键精灵（python加强版）
items: 如何正确用Python截取屏幕
items: 《Python网络数据采集》-Ryan Mitchell（笔记）
items: 《Learn Python the Hard Way/笨办法学python》（第三版）-Zed Shaw（笔记）
items: python中函数的多层嵌套与nonlocal
items: letterGirls.setdefault(girl[0], []).append(girl)：setdefault返回对象与append应用
items: python中format方法输出{}的应用
items: 《A Byte Of Python3》-Swaroop.C.H（笔记）
items: 如何压缩图片

《深度学习入门 基于Python的理论与实现》-斋藤康毅（笔记）
type: item
date: 2025-12-17T14:48:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4260/，转载请注明出处。本文的原文写作日期为2020年11月17日，主要目的是总结《深度学习入门 基于Python的理论与实现》。笔者的毕业论文有很多东西来自这本书。下面的内容有些缩进或者图片缺失，可以参考 原word文档 。本书主要用numpy来处理运算，用matplotlib将结果可视化。对于没有基础的人十分友好，只需要高中的线代知识就可以看懂。 1.x=x.flatten() 将矩阵及张量转换为一维数组。x>15，结果得到一个由True和False组成的一维列表，x[x>15]即可输出所有大于15的成员。 矩阵与一维数组的*乘，（数组长度与矩阵列数相同）将一维数组扩张为矩阵形状后简单相乘，符合交换率，符号为*； 矩阵与数组dot乘，（数组长度与矩阵列数相同）将一维数组与每行对应索引相乘求和，得到一维数组，长度为矩阵的行数：如[[1, 2], [3, 4], [7, 8]] dot [5,6]，则得[1*5+2*6, 3*5+4*6,7*5+8*6]，不符合交换律，用np.dot计算。 一次绘图流程：p42 2.感知机：接受一个或多个输入，输出一个信号。有多个输入时，可以给各个输入配置权重。机器学习就是人给机器一些数据，机器根据这些数据选出权重的过程。 P56从图像上，感知机是一条直线，有局限性。叠加多个感知机可以构造类似曲线。 3.对于单层感知机，实际上有两个函数，比如首先有y=b+x1*w1+x2*w2，其中b为偏置，w1、w2为权重；然后通过激活函数，比如h(x)=1或0（当y<=0时为0，否则为1。这种函数的输出是跳跃的，可称为阶跃函数）。若把激活函数换成其他形式，就接近神经网络的概念了。常用的一个激活函数（sigmoid函数）：1/(1+exp(-x))，其中exp(-x)为e的-x次方。 接受numpy数组为参数的阶跃函数见p69。 激活函数也可以使用ReLU函数，其在x<=0时输出0，在x>0时则为线性关系。P74 对于输出层的激活函数，如果是分类问题（类似阶跃函数）用softmax函数，回归问题（连续输出数值）用恒等函数。P89 softmax函数的输出是连续的，总和为1，可以看作概率。为了节省算力，对未知模型进行预测时通常也可以省略输出层的softmax激活函数（接受数据进行学习时可以不省略）。 在分类问题中，输出层的神经元数量通常等于类别的数量。哪个神经元的输出最大，就会归类为该类别。 4.正规化：将数据进行处理，使其限制在某个范围内。正规化是一种预处理。 批处理：相同的神经网络，多个输出，多个结果。批处理可以大大加快运算速度。P101 5.损失函数：描述当前神经网络与测试数据（即监督数据）在多大程度上不拟合。一般可用均方误差函数和交叉熵。均方考虑了非正确解、越接近0（越小）越好，交叉熵只包含正确解、越接近0（越小）越好。 机器学习就是要使得损失函数值最小。如果训练数据太多，可以从中随机选择部分数据来学习，称为mini batch。 不用精确度作为评价标准，因为要设定参数的导数（变化梯度），如果用精确度为指标，容易导致导数为0，参数无法更新（精确度常常是跳跃的，微调无法产生影响，而损失函数是连续变化的）。这也是sigmoid函数优于阶跃函数的地方（激活函数）。 对于矩阵，y[0,2]的写法等同于y[0][2] 梯度指示的方向是损失函数减少量最多的地方，不一定指向损失函数值最小的地方。所以，机器学习可能会陷入局部最小值、鞍点或者学习平原。 鞍点处的梯度也为0，比如一个马鞍形曲面，(0,0,0)处的形状就很像马鞍。 梯度，就是一个一维数组。一个函数有多个输入，那么梯度就是这个多维函数（在某一点处）的导数。梯度数组的大小和输入多少相等，意义是对每一个输入，在保持其他输入不变时求该输入的导数，最终组成一个导数数组。为了使损失函数减小，需要沿负梯度方向下降。 6.反向传播法算梯度的速度比微积分法快许多，主要应用了复合函数的求导（相乘）。 7.有时SGD（随机梯度下降），即沿着梯度最大的地方下山的方法，不一定能最快下山。还有其他一些方法。 Momentum（动量法），如果某一方向上的梯度较小，但是持续很久，就适合用这种方法。模拟静止小球在山中的运动，某一方向累计的梯度会给小球积累该方向的速度，于是在该方向上移动越来越快。 AdaGrad（Adaptive适应梯度法），对梯度中的每一个导数都有一个学习率，该学习率还会不断衰减。AdaGrad是通过记录过去所有梯度的平方和实现的，最终学习率会衰减到0。不想让学习率衰减太快可以用RMSProp法，其会更多地考虑最近的梯度、逐渐减小久远梯度的权重。 Ada…

按键精灵（python加强版）
type: item
date: 2025-12-17T14:38:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4259/，转载请注明出处。本文的原文写作日期为2020年10月22日，主要目的是用Python重构按键精灵。主体程序，主要是一些功能的实现，具体应用需要自己写。写的比较乱：import win32gui, win32api, win32con, win32ui import time from time import sleep import random from random import uniform import logging from logging import info, warning, error from config import VK_CODE import copy import cv2 as cv import traceback # mode为test意为调试模式，real则为实际应用 # In 'test' mode, it will print some hidden info for Debug mode = 'test' # 模式图的存储路径 # The save path of pattern pics pattern_path = 'yourpath\\' # 设置logging的书写格式 # Setting logging configs logging.basicConfig( level=logging.DEBUG, format= '%(lineno)d : %(asctime)s : %(levelname)s : %(funcName)s : %(message)s', filename='yourpath\\log{}.txt'.format( time.strftime('-%Y-%m-%d')), filemode='w') # 用当前时间初始化随机数 # Set random seed random.seed(time.time()) def Get_PosAndHwnd(hwnd=0, ClassName=None, TitleName=None): '''接受句柄、类名、标题名，返回第一个匹配的窗口位置和句柄。 Accepts Handle, ClassName or TitleName of a window, returns the rect-pos of the first window that matches. Args: hwnd: 目标句柄 target handle. ClassName: 目标窗口类名 target ClassName. TitleName: 目标窗口标题 target TitleName. Returns: x1, y1, x2, y2, hwnd 前四个参数描述窗口在显示器中的位置，hwnd为句柄。 x1-y2 describes the pos of the window in screen, last arg is the handle. ''' try: if hwnd == 0: hwnd = win32gui.FindWindow(ClassName, TitleName) x1, y1, x2, y2 = win32gui.GetWindowRect(hwnd) info('找到窗口，句柄：{}，标题名：{}，类名：{}，坐标：{}'.format( hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd), (x1, y1, x2, y2))) return x1, y1, x2, y2, hwnd except: global mode if mode == 'test': traceback.print_exc() elif mode == 'real': error('Get_PosAndHwnd 出现错误') def Activate_Hwnd(hwnd): '''激活指定句柄的窗口。每次转换时使用。 Activates the window with the matching hwnd. Args: hwnd: 目标句柄 target handle. Returns: No return. ''' try: win32gui.SendMessage(hwnd, win32con.WM_ACTIVATE, win32con.WA_ACTIVE, 0) # WA_CLICKACTIVE为通过鼠标激活，WA_ACTIVE为鼠标以外的东西（如键盘）激活，WA_INACTIVE为取消激活 # WA_CLICKACTIVE …

如何正确用Python截取屏幕
type: item
date: 2025-12-17T14:33:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4257/，转载请注明出处。本文的原文写作日期为2020年10月21日，主要目的是用Python截取屏幕。最近需要对窗口截图，看到了以下文章：https://www.cnblogs.com/Evan-fanfan/p/11097850.html其中有些错误（乱写文章害人不浅啊）。经过我2天实验，大概搞清楚了3个关键api的用处。注释和代码如下：# 根据句柄、截图位置和图片路径，对窗口的客户区截图并存到指定位置 # GetDC一类的需要用ReleaseDC释放，CreateDC一类的用DeleteDC释放，DeleteObject则删除一个逻辑笔、画笔、字体、位图、区域或者调色板， def ClientRect_PrtSc(hwnd, area=None, filename=''): try: hwnd = hwnd if filename == '': filename = 'C:\\Users\\tadio\\Desktop\\helper\\pics\\targets\\{}.bmp'.format( hwnd) hwndDC = win32gui.GetDC( hwnd) # 获取窗口的设备上下文Device Context。GetWindowDC包括了非客户区，而GetDC仅为客户区 mfcDC = win32ui.CreateDCFromHandle(hwndDC) # 获取mfcDC saveDC = mfcDC.CreateCompatibleDC() # 创建可兼容DC saveBitMap = win32ui.CreateBitmap() # 创建bitmap以保存图片 '''MonitorDev = win32api.EnumDisplayMonitors( None, None) # 获取显示器信息，枚举显示器，笔记本据说可能有问题''' x1, y1, x2, y2 = win32gui.GetClientRect( hwnd) #GetClientRect获取客户区窗口位置，GetWindowRect获取整个窗口的位置信息 x, y, w, h = (0, 0, 0, 0) if area == None: x = 0 y = 0 w = x2 - x1 h = y2 - y1 else: x, y, m, n = area w = m - x h = n - y saveBitMap.CreateCompatibleBitmap(mfcDC, w, h) # 为bitmap开辟空间 # 对saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)的理解： # 1.mfc相当于一个虚拟屏幕。这里的参数w和h决定了这个屏幕的大小。 # 2.屏幕的初始状态是黑色，每个坐标都是#000000 # 3.之前有mfcDC = win32ui.CreateDCFromHandle(hwndDC)，又有hwndDC = win32gui.GetDC(hwnd) # mfcDC和hwnd窗口之间建立了某种关联，可以将hwnd窗口中的图像放到虚拟屏幕上 saveDC.SelectObject(saveBitMap) # 将截图保存到saveBitMap中 saveDC.BitBlt((0, 0), (w, h), mfcDC, (x, y), win32con.SRCCOPY) # 对saveDC.BitBlt(坐标1, (w, h), mfcDC, 坐标2, win32con.SRCCOPY)的理解： # BitBlt的功能大概是把从hwnd窗口截到的图放到虚拟屏幕上，信息转入saveDC。 # 1.坐标1是针对窗口截图的，指定截图放在黑色背景上的位置（指定左上角） # 2.w和h窗口截图的长宽，而坐标2指定了开始截图的位置 # 这两个参数决定了从hwnd窗口的哪里截图、截多大的图 # 3.mfcDC已经和hwnd窗口建立了关联，所以不需要指定虚拟屏幕从哪个窗口获得截图 # 4.SRCCOPY意为将截图直接拷贝到虚拟屏幕中 # 接下来的saveBitMap.SaveBitmapFile(saveDC, filename)则是对虚拟屏幕截图并保存到指定位置 saveBitMap.SaveBitmapFile(saveDC, filename) # 清除数据 win32gui.DeleteObject(saveBitMap.GetHandle()) saveDC.DeleteDC() mfcDC.DeleteDC() win32gui.ReleaseDC(hwnd, hwn…

《Python网络数据采集》-Ryan Mitchell（笔记）
type: item
date: 2025-12-17T14:05:01+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4247/，转载请注明出处。本文的原文写作日期为2020年9月17日，主要目的是总结《Python网络数据采集》。下面的内容有些缩进或者图片缺失，可以参考 原word文档 。1.本书使用标准urllib模块和非标准模块bs4模块： from urllib.request import urlopen from bs4 import BeautifulSoup html = urlopen("http://www.pythonscraping.com/pages/page3.html") bsObj = BeautifulSoup(html) 2.find_all()方法相关： find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs) method of bs4.BeautifulSoup instance 第一个参数name为标签名，为None时可匹配所有标签名； 第二个为标签属性，常以字典形式给出； 第三个为是否递归查找，除非十分了解网页格式且有时间要求，一般情况下都取True； 第四个为匹配标签内容； limit为查找返回个数限制，为1时该方法等同find方法； 最后是一些其他参数。 3.html格式相关： 子节点（children）和后代节点（descendant），子节点仅为下一级的标签，后代节点包含所有下级标签： for child in bsObj.find("table",{"id":"giftList"}).children: print(child) 这些相关节点都是包含空格、换行的，处理时务必去掉 兄弟标签：next_siblings为后续的所有同级标签，previous_siblings相反。这两个都有去掉s的形式。 父标签与祖先标签：parent和parents 4.常用re符号： 5.用attrs方法返回一个标签的所有属性（字典形式） 6.scrapy应用：自学 7.API，应用编程接口，有严格的语法，用XML或json表示数据。 HTTP常用方法：get，请求网页信息；post，用户提交信息；put，请求更新某个数据；delete，请求删除某个数据。 8.使用twitter库获取推文、更新推文等；利用google、baidu提供的API。 9.用urllib.request.urlretrieve下载文件 10.学习mysql mysql基础命令： net start mysql 启动sql网络服务；CREATE DATABASE scraping 创建数据库；USE scraping 使用数据库； >CREATE TABLE pages (id BIGINT(7) NOT NULL AUTO_INCREMENT, title VARCHAR(200), content VARCHAR(10000), created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id)); 用以上头创建数据库中的表； > INSERT INTO pages (title, content) VALUES ("Test page title", "This is some te st page content. It can be up to 10,000 characters long."); 向表中插入数据； >SELECT * FROM pages WHERE title LIKE "%test%"; 查找数据； 删除只需要把对应的SELECT换成DELETE即可。记得先确认，加上WHERE。 >UPDATE pages SET title="A new title", content="Some new content" WHERE id=2; 更新数据。 ALTER DATABASE scraping CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci; 将scraping数据库的字符集从utf8mb4改为utf8mb4_unicode_ci。 用pymysql在python中使用mysql： import pymysql conn = pymysql.connect(host='127.0.0.1', user='root', passwd='aboutime', db='mysql')# 创建连接对象 cur = conn.cursor()# 创建游标对象 cur.execute('U…

《Learn Python the Hard Way/笨办法学python》（第三版）-Zed Shaw（笔记）
type: item
date: 2025-12-17T13:51:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4242/，转载请注明出处。本文的原文写作日期为2020年9月17日，主要目的是总结《Learn Python the Hard Way/笨办法学python》（第三版）。下面的内容有些缩进或者图片缺失，可以参考 原word文档 。总结：这本书适合自学能力较强的，或者有一定基础的人自学。 1.格式化输出：%s用于string（基于str()），%r用于debug（基于repr()，原封不动显示输出，双引号转换为单引号），%d用于整数。format更先进。 2.sys.argv：脚本接受的参数列表。[0]为脚本路径。 3.文件操作：f=open(文件名,’w’)。常用方法：f.close()、read()、readline()、truncate()、write(字符串)等。注意方法的参数。 4.f.seek(整数)将读/写指针放到指定位置。 5.str.split(‘ ’)以空格为标志分割str，返回列表。 列表.pop(x)弹出（即删除）列表[x]元素，返回这个元素。 sorted()整理一个列表或元组等。 6.一些关键字： global：在函数中定义的变量默认是局部变量，局部变量覆盖同名全局变量。引入全局变量需要用global。 assert（断言）：判断后面跟着的表达式，若值为False则立刻终止程序并触发一个assert错误。 pass：用来占位。 yield：在函数中遇到yield后，会将所有局部变量保存，返回yield后面的对象，然后继续执行函数。yield主要是为了节省空间。 exec：将字符串当作python语句执行。总是返回None。 7.使用 字典名.items()来遍历字典。字典的get方法：get(key,default)用键找到对应的值，若没有则返回default，默认为None。 8.super方法：为了使子类调用父类方法可使用super方法。在python3中，格式为super().父类方法。在复杂的继承中，super调用的哪个方法可能比较复杂。 为了以一定的顺序快速寻找到指定方法，python使用了MRO（Method Resolution Order）方法解析顺序，涉及到C3算法。应该尽量避免多重继承。 9.str.strip([chars])方法：去除str两端的chars字符串，默认为去除空白符。 10. random库： >>> import random >>> random.choice(['apple', 'pear', 'banana'])'apple' >>> random.sample(range(100), 10) # sampling without replacement [30, 83, 16, 4, 8, 81, 41, 50, 18, 33] >>> random.random() # random float 0.17970987693706186 >>> random.randrange(6) # random integer chosen from range(6)4 11.后面可以不用看了

python中函数的多层嵌套与nonlocal
type: item
date: 2025-12-17T13:50:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4241/，转载请注明出处。本文的原文写作日期为2020年9月6日。本文的目的如标题所示。阅读《python基础教程第三版》第六章提到了函数及其作用域的嵌套。nonlocal为内部函数指定外部函数中的变量时使用。如果函数是三层嵌套会如何呢？我写了如下代码用于验证：def out(): x = 100 def middle(): x = 10 def mini(): nonlocal x print(x) return mini return middle out()()()结果输出了10。可见nonlocal有就近的原则。为了在mini中能够调用out中的x，我试着在mini中使用out.x或者声明global x，但都出现了错误。问题：如果出现了多层函数嵌套，在内层函数中应该如何指定使用哪一个作用域中的变量？

letterGirls.setdefault(girl[0], []).append(girl)：setdefault返回对象与append应用
type: item
date: 2025-12-17T13:48:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4239/，转载请注明出处。本文的原文写作日期为2020年9月6日。本文的目的如标题所示。《python基础教程第三版》第五章有一例：girls = ['alice', 'bernice', 'clarice'] boys = ['chris', 'arnold', 'bob'] letterGirls = {} for girl in girls: letterGirls.setdefault(girl[0], []).append(girl) print([b+'+'+g for b in boys for g in letterGirls[b[0]]])目的是配对首字母相同的boy与girl并据此创建列表。关键在于理解letterGirls.setdefault(girl[0], []).append(girl) 。书上说append方法不能用于字典，看上去好像这一句错了。其实可以从左向右看：letterGirls是一个字典，对字典使用setdefault方法，参数为(girl[0], [])，即对girls列表中的每一个字符串元素，以其首字母为键查找字典中对应值，该键不存在则创建 首字母: [] 的项。setdefault返回的是值，也就是[]空列表，然后对空列表使用append方法，原位将空列表修改为[girl]。这一步后输出字典，得到：{'a': ['alice'], 'b': ['bernice'], 'c': ['clarice']}最后一行，关键在于for g in letterGirls[b[0]]。以b的首字母为键得到值g，然后打印b+g。这里的问题是值g好像是一个一元字符串列表，列表和字符串是不能用+操作并输出的。但如果写print([type(g) for b in boys for g in letterGirls[b[0]]])就会发现，g的类型是str类。这是因为in操作，letterGirls[b[0]]才是一个一元字符串列表，for g in 字符串列表，那么就会得到这个字符串了。上面的：letterGirls.setdefault(girl[0], []).append(girl) 也可以替换成：letterGirls.setdefault(girl[0], [girl])注意不能写成：letterGirls.setdefault(girl[0], girl)（这时for g in 字符串，则会输出一个一个的字符）原因已在上面说明了。

python中format方法输出{}的应用
type: item
date: 2025-12-17T13:38:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4232/，转载请注明出处。本文的原文写作日期为2020年9月5日。本文的目的如标题所示。看《笨方法学python第三版》的时候习题46，想写一个python脚本自动在当前目录下创建项目骨架。其中需要将一些内容写入一个文件，需要用到format方法，但出现了一个问题。简化版的问题代码如下：project_name = 'test' setup_config = ''' config = { 'description': '{0}', 'author': 'Author Name', } '''.format(project_name) print(setup_config)运行时出现异常：KeyError: "\n 'description'"KeyError是查找字典中的键时键不存在返回的错误。作为替代方法，我暂时先用了%格式化输出：project_name = 'test' setup_config = ''' config = { 'description': '%s', 'author': 'Author Name', } ''' % project_name print(setup_config)可以正常运行 。我想到了在format中用{{}}来输出{}的问题，多试几次，发现：project_name = 'test' setup_config = ''' config = {{ 'description': '{0}', 'author': 'Author Name', }} '''.format(project_name) print(setup_config)就可以正常运行，但第一段的代码中{0}是高亮显示的。我猜测可能是format方法中，误以为：{ 'description': '{0}{到:这之间的内容是键，: 后面的是指定格式，但我没有给出键，因为想使用0作为键。由于我使用的vs code高亮了{0}，可能解释器和编辑器的理解不一样。总结：要用format方法输出{}，不论出现在字符串的哪里，都应该使用双括号来替代{}，才可以正确识别。

《A Byte Of Python3》-Swaroop.C.H（笔记）
type: item
date: 2025-12-17T13:33:00+00:00
description: 步骤/目录： 无本文首发于个人博客https://lisper517.top/index.php/archives/4230/，转载请注明出处。本文的原文写作日期为2020年9月4日，主要目的是总结《A Byte Of Python3》。下面的内容有些缩进或者图片缺失，可以参考 原word文档 。1.python中有整数、浮点数、复数。整数受限于内存大小。双引号等同于单引号，用三引号来指示多行字符串。表示’，可以\’，或者在头尾使用双引号，或者使用三引号。行末的\表示下一行与本行之间没有换行符。类似C++中的raw string，前面加r或R可指定自然字符串。相邻的字符串会被自动连接。 输出中的format方法，类似printf+setf，可以调整格式。 标识符不能以数字开头，大小写敏感，只能用数字、字母、下划线。可以使用中文。 python中的任何东西都是对象。 变量不需要声明类型，可以直接初始化。 python默认一行一句，若一行多句可用;间隔。使用缩进来决定语句的层次， 2.定义了字符串与整数的*操作；x**y为x的y次方；定义了浮点数的%求余；//为取整除 - 返回商的整数部分（向下取整）；&、|、^为按位与、或、异或；~x为-(x+1)；比较操作符可连接；not为非操作，类似!；and、or为和、或操作；in和not in为从属关系，is和not is为是否关系。优先级见p25。 3.有if、while、for三种控制流语句，没有switch，某些场合下用字典代替。条件后跟:，while后可选else，for后也可选else。break用于跳出，注意，对应的else部分不会执行；continue。 4.range函数，提供第一个参数到第二个参数的序列（不含第二个参数），步长为1，可用第三个参数调整步长。len函数返回字符串的长度。 5.函数：用关键字def定义，如 def 函数名(参数表): 函数体 使用global语句来调用block外的变量。可以同时声明多个变量。 非局部：用于定义函数中的函数，介于局部和全局之间，nonlocal 函数的参数默认值也需要从右到左，但调用时可以只给出其中几个值而忽略其他值来使用默认参数，这时参数的顺序可以乱序。 参数个数不确定，可以使用*。单个*可以将参数收集为一个列表，**则可以将参数收集为字典。*后面要输入非列表中的参数，需要用keyword-only参数，如果仅想使用keyword-only参数，可以使用*后面不带名字，然后接一个k-o参数。 return用于退出函数，单独的return等同return None。pass代表空语句块。 Docstring，在模块、类或者函数中，用三引号括起来的部分，是该部分的说明。使用print(对象名.__doc__)可以打印其说明文档。其首行以大写字母开始、句号结束，第二行为空行，第三行开始说明。help就是抓取docstring，按q可退出help。 6.模块：类似C中多个源文件。要使用某个模块，可import之，如果不是内置的模块，解释器会在sys.path中列出的路径中查找（其第一个元素就是当前目录），找到后运行这个模块，这个初始化过程仅在第一次导入时运行。 在执行python XXX.py 参数表 时，会将参数表传递给XXX.py模块，用sys.argv列表可查看参数列表，其中sys.argv[0]元素是脚本名称。查看os.getcwd()可获取当前目录。 为了使导入模块变快，会自动创建按字节编译的pyc文件，在当前目录，若没有写权限则不会创建。pyc文件与平台无关。 如果想导入sys中的argv、使其可以直接使用而不加sys.，可from sys import argv，或者导入sys中全部：from sys import *（但不会导入双下划线开头的对象），一般应避免这样使用。 每个模块都有__name__，若其为’__main__’说明这个模块类似含有main函数。此可用来避免import模块时其自动运行一次。 dir()函数可以列出模块中的标识符（类，函数，变量），给其空参数则会列出本模块的标识符。del语句可以删除变量或名字。 包是一个文件夹，含有多个模块，其中有一个__init__.py文件来指明该文件夹包含python模块。包可嵌套。 7.数据结构：列表、元组、字典、集合。 列表list用[]包括，元素间用逗号分隔，有序。可以用append方法来在列表尾部添加元素。对列表使用len会计数其元素个数。列表还可以使用sort方法，或者用del删除某个元素。列表中的元素类型可以不同，比如一个字符串和整数在同一个列表中。列表可嵌套。 元组和列表类似，但像字符串一样不可变，用()包括（也可以不带括号）。含一个元素的元组需要在…

如何压缩图片
type: item
date: 2022-10-19T03:38:00+00:00
description: 步骤/目录： 1.需求介绍 2.ffmpeg 3.tinypng 4.squoosh （1）Node.js （2）克隆仓库并安装运行 a.本地运行网页服务器 b.运行桌面版 c.squoosh-cli （3）squoosh的使用 5.修改vimg_processor_multi本文首发于个人博客https://lisper517.top/index.php/archives/60/，转载请注明出处。本文的目的是介绍一些图片压缩的工具和使用方法。本文写作日期为2022年10月19日。运行的平台为win10，编辑器为VS Code。1.需求介绍在处理前端时，常常需要放一些图片在网页中，但是一般素材图片占用空间都很大，直接放到网页上不太合适，如果有方法把图片压缩一下就very的nice。本文就介绍一些图片压缩的工具和方法。2.ffmpeg在之前的文章 Python，爬虫与深度学习（17）——电影的信息爬取、下载与处理（二） 中，笔者用python写了一个vimg_processor类，主要是用ffmpeg来获取图片/视频信息、压缩图片/视频。其中使用ffmpeg压缩图片的命令参考了 这篇文章 ，如下：'ffmpeg -i "{}" -vf palettegen=max_colors=256:stats_mode=single -y "{}"'.format(self.origin_abs_path, self.palette) 'ffmpeg -i "{}" -i "{}" -lavfi "[0][1:v] paletteuse" -pix_fmt "{}" -y "{}"'.format(self.origin_abs_path, self.palette, self.pix_fmt, self.temp_img) 'ffmpeg -i "{}" -vf scale={} -y "{}"'.format(self.temp_img, self.definition, self.compressed_abs_path)总的来说是使用调色板将原图使用的256色减少，然后根据调色板输出图片，最后再压缩图片尺寸。笔者其实不太了解ffmpeg，使用上面的命令，虽然图片占用空间能压缩到很小，但色彩减少导致肉眼能看出很多差距，比较明显的是在人像中，如果涂了口红，压缩后的图片会呈现一种灰红色的质感，这是无法接受的。经过一番寻找，笔者发现了其他压缩图片的方法，它们压缩图片的算法比较复杂，效果也远非简单的3句ffmpeg命令可比。3.tinypngTinyPNG 据说是一个久负盛名的图片压缩网站，可惜它的压缩算法没有开源。如果你只是想压缩几张图片，可以到它的网址 https://tinypng.com/ 手动上传图片，据说每天只能上传20张不超过5MB的图片；如果需要批量压缩图片，你可以到 https://tinypng.com/developers 填写姓名、邮箱申请一个API key（限制是每月只能压缩500张），然后使用python或者其他语言写一个客户端实现压缩脚本，可以参考 这个项目 。使用TinyPNG确实压缩效果不错，可惜源码不开源，而且能压缩的图片张数有限制（据说有方法开源绕开限制，参考 这篇文章 ，原理是tinypng服务器限制上传次数时用到了ip进行判断，所以在构造请求头时修改了ip）。综合考虑下来，笔者放弃了TinyPNG，毕竟万一哪天这类闭源工具开始收费就不太合适了。像TinyPNG这样的在线图片压缩网站还有很多，比如：https://tinyjpg.com/ （TinyPNG的系列网站）https://imagestool.com/zh_CN/compress-images.htmlhttps://squoosh.app/本文将重点介绍squoosh。4.squooshsquoosh 是google chrome labs推出的一款开源图片压缩工具，源码放到了github上： https://github.com/GoogleChromeLabs/squoosh ，这些源码主要是TypeScript、JavaScript写的，但是笔者希望用python调用这个图像压缩的工具，这需要一些技巧，下面以Win10为例讲解。（1）Node.js因为要用JavaScript，需要安装Node.js、npm。按照 runoob教程 ，进行如下操作：到 https://nodejs.org/zh-cn/download/ 下载对应的安装包，笔者选择的是14.15.1的64位Windows安装包（下载地址为 https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi ，因为在 这个问题 中提…