-
好久不见写这篇文章只是想证明一下:本博主还在呼吸许久未更,甚是想更呐~这段时间生活中充斥着各种事情,感觉每天都在忙忙碌碌,偶而停下疲惫的身躯,突然抬头,却不知自己身处何方,忙了这么久,到底在忙些什么呢?找不着方向,于是开始惶恐,便又不知方向的胡乱奔走……,好吧好吧,总结两个字:迷茫,再加两个字:瞎忙……其实这几天一直想写博客的,想写有趣又轻松的一篇文章,但又不到写哪些内容比较好,又因还要解决各种事情,于是就搁到了现在……直到某天,为了完成MOOC(MOOC不会没人不知道吧)上的回复讨论任务,我不已为然的点开了MOOC……突然?我看到了一个进度条,那个进度条仿佛就像是深渊,脑海中突然闪出一句话,我%@#!,咳咳咳,不是不是,是一句名言:当你凝望深渊,深渊也在凝望着你……(进度条是已经用代……不是,是已经用我辛勤的劳动把它拉起来的)不知到有没有小伙伴经历过要回复几十条讨论的经历,当场看见那进度条我就……,就偷偷写脚本了这个脚本花了我比较长的时间才完成的,因为调试的过程有些许麻烦……,不过最终还是解决了,想看效果如何,请往下看实现过程老操作了兄弟们~又双叒叕是Get_cookie.py了兄弟,看过我《小玩意儿》专栏文章的都能看烂了,但别说,还真好用,登录一次,一劳永逸,就靠它了~,话不多说,直接上号上码(记得在三十秒内登录哦~) from selenium import webdriver import time import json driver = webdriver.Chrome() driver.maximize_window() driver.get('https://www.icourse163.org/') time.sleep(30) dictCookies = driver.get_cookies() jsonCookies = json.dumps(dictCookies) # 转换成字符串保存 with open('moocCookie.txt', 'w') as f: f.write(jsonCookies) print("cookies保存成功") 一步拿捏讨论以前回复讨论咱们讲究的是什么?讲究的是灵活运用Ctrl C和Ctrl V,讲究的是快准狠现在回复讨论咱们讲究的是什么?讲究的是能不用手就不用手,讲究的是一个 automation,科技是第一生产力呀兄弟们 什么?相应模块怎么下载?pip install 模块名 就完事了兄弟~实现代码话不多说码来 from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import json import time class MOOC(object): def __init__(self): self.driver = webdriver.Chrome() self.driver.get('https://www.icourse163.org/') def login(self): #获取保存下的cookie值 with open('moocCookie.txt', 'r', encoding='utf-8') as f: listCookies = json.loads(f.read()) # 往driver里添加cookie for cookie in listCookies: cookie_dict = { 'domain': '.icourse163.org', 'name': cookie.get('name'), 'value': cookie.get('value'), 'expires': '', 'path': '/', 'httpOnly': False, 'HostOnly': False, 'Secure': False } self.driver.add_cookie(cookie_dict) self.driver.refresh() # 刷新页面 # 进入课程 def entering_the_course(self): #等待“个人中心”元素出现 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located((By.XPATH, '//*[@id="j-indexNav-bar"]/div/div/div/div/div[7]/div[3]/div/div/a/span')) ) self.driver.find_element(By.XPATH, '//*[@id="j-indexNav-bar"]/div/div/div/div/div[7]/div[3]/div/div/a/span').click() # 等待“SPOC课程12”元素出现并点击 time.sleep(1) WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located((By.XPATH, '//div[@class="u-selectTab-container"]/div[2]/a')) ) self.driver.find_element(By.XPATH, '//div[@class="u-selectTab-container"]/div[2]/a').click() #等待课程元素出现,并获取元素,用户选择课程 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located((By.XPATH, '//div[@class="course-card-wrapper"]/div/a/div/img')) ) course_ele = self.driver.find_elements(By.XPATH, '//div[@class="course-card-wrapper"]/div/a/div/img') course_name = [ele.get_attribute('alt') for ele in course_ele] for index, i in enumerate(course_name): print(index, i) user = int(input('请输入课程序号:')) course_ele[user].click() time.sleep(2) self.driver.switch_to.window(self.driver.window_handles[-1]) # 切换窗口 time.sleep(2) #等待课件出现并点击 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located((By.XPATH, '//li[@data-name="课件"]')) ) self.driver.find_element(By.XPATH, '//li[@data-name="课件"]').click() # 等待章节元素出现并点击 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located((By.XPATH, '//div[@class="m-learnChapterList f-pr"]/div[@class="m-learnChapterNormal f-pr"][1]')) ) # 点击章节 self.driver.find_element(By.XPATH, '//div[@class="m-learnChapterList f-pr"]/div[@class="m-learnChapterNormal f-pr"][1]').click() time.sleep(0.3) # 点击进入视频 self.driver.find_elements(By.XPATH, '//div[@class="sourceList"]/div[1]')[0].click() # 获取章节中”选择课程“的元素并点击 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located( (By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div')) ) # 获取所有章节 temp_chapters = self.driver.find_elements(By.XPATH, '//div[@class="f-fl j-chapter"]//div[@class="down f-bg j-list"]/div') # 通过循环获取到的章节元素和课程元素,进行讨论 for chapter_index in range(len(temp_chapters)): # 循环章节 # 获取章节中”选择课程“的元素并点击 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located( (By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div')) ) # 获取章节选项框并点击 self.driver.find_element(By.XPATH, '//div[@class="f-fl j-chapter"]/div[@class="u-select"]/div[1]').click() self.driver.find_elements(By.XPATH, '//div[@class="f-fl j-chapter"]//div[@class="down f-bg j-list"]/div')[chapter_index].click() # 等待课程元素出现 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located( (By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div')) ) # 获取章节中所有课程 course = self.driver.find_elements(By.XPATH,'//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div/div[2]/div') course_names = [i.get_attribute('title') for i in course] for c_index in range(len(course)): # 循环课程 WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located( (By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div')) ) self.driver.find_element(By.XPATH,'//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div').click() WebDriverWait(self.driver, 1000).until( EC.presence_of_element_located( (By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div/div[2]/div')) ) # 重新获取课程元素并点击 course1 = self.driver.find_elements(By.XPATH, '//div[@class="j-breadcb f-fl"]//div[@class="f-fl j-lesson"]/div/div[2]/div') course1[c_index].click() time.sleep(2) try: try: # 获取讨论元素 disc = self.driver.find_element(By.XPATH, '//li[@title="讨论:讨论话题"]/span[2]') if disc.is_enabled(): # 如果讨论元素存在且可以点击 disc.click() self.discuss() # 调用讨论函数 except: time.sleep(0.5) if course_names[c_index] == '讨论区': self.discuss() except: pass # 讨论 def discuss(self): # 等待“回复”元素出现 WebDriverWait(self.driver, 100).until( EC.presence_of_element_located((By.XPATH, '//div[@class="optbar f-cb"]/a[1]/span')) ) time.sleep(0.5) self.driver.execute_script("var q=document.documentElement.scrollTop=10000") time.sleep(0.5) try: content = self.driver.find_element(By.XPATH, '//div[@class="j-list"]/div/div[3]/div/div[2]/p').text except: content = self.driver.find_element(By.XPATH, '//div[@class="j-list"]/div/div[1]/div/div[2]').text self.driver.switch_to.frame(0) time.sleep(0.5) # 定位输入框并输入信息 self.driver.find_element(By.XPATH, '//body[@contenteditable="true"]').send_keys(content) self.driver.switch_to.window(self.driver.window_handles[-1]) # 进行窗口切换 time.sleep(1) # 点击发送回复 self.driver.find_element(By.XPATH,'/html/body/div[5]/div[2]/div[4]/div[2]/div/div[1]/div/div/div[3]/div[2]/div[2]/div/div/div[5]/div/div[1]/div[2]/a[1]').click() def run(self): self.login() self.entering_the_course() mooc = MOOC() mooc.run()
-
import os import cv2 import numpy as np import math # 检测针脚位置 def needelCenter_detect(img): params = cv2.SimpleBlobDetector_Params() # Setup SimpleBlobDetector parameters. # print('params') # print(params) # print(type(params)) # Filter by Area. params.filterByArea = True params.minArea = 100 params.maxArea = 10e3 params.minDistBetweenBlobs = 50 # params.filterByColor = True params.filterByConvexity = False # tweak these as you see fit # Filter by Circularity params.filterByCircularity = False params.minCircularity = 0.2 # params.blobColor = 0 # # # Filter by Convexity # params.filterByConvexity = True # params.minConvexity = 0.87 # Filter by Inertia # params.filterByInertia = True # params.filterByInertia = False # params.minInertiaRatio = 0.01 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Detect blobs. minThreshValue = 110 _, gray = cv2.threshold(gray, minThreshValue, 255, cv2.THRESH_BINARY) # gray = cv2.resize(gray, dsize=None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR) # plt.imshow(gray) # cv2.imshow("gray",gray) # 找到距离原点(0,0)最近和最远的点 detector = cv2.SimpleBlobDetector_create(params) keypoints = detector.detect(gray) # print(len(keypoints)) # print(keypoints[0].pt[0]) # 如果这儿没检测到可能会出错 if len(keypoints) == 0: print("没有检测到针角坐标,可能需要调整针角斑点检测参数") return keypoints else: print(len(keypoints)) im_with_keypoints = cv2.drawKeypoints(gray, keypoints, np.array([]), (255, 0, 0), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) # if keypoints is not None: color_img = cv2.cvtColor(im_with_keypoints, cv2.COLOR_BGR2RGB) # 画出圆的圆心 cv2.circle(color_img, (int(keypoints[0].pt[0]), int(keypoints[0].pt[1])), 5, (0, 255, 0), -1) cv2.imshow("color_img",color_img) # cv2.waitKey() return keypoints # 检测连接器圆形位置 def circle_detect(image): # 灰度化 circle_img = image.copy() gray = cv2.cvtColor(circle_img, cv2.COLOR_BGR2GRAY) # 输出图像大小,方便根据图像大小调节minRadius和maxRadius # print(image.shape) # 进行中值滤波 img = cv2.medianBlur(gray, 3) # 针角圆心坐标 out_x = 0 out_y = 0 # 霍夫变换圆检测 circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 10e10, param1=100, param2=30, minRadius=10, maxRadius=100) # 如果没检测到会报错 # 这种判断方式过于简单 if circles is None: print("没有检测到连接器外圆") else: for circle in circles[0]: # 圆的基本信息 # print(circle[2]) # 坐标行列-圆心坐标 out_x = int(circle[0]) out_y = int(circle[1]) # 半径 r = int(circle[2]) # 在原图用指定颜色标记出圆的边界 cv2.circle(circle_img, (out_x, out_y), r, (0, 0, 255), 2) # # 画出圆的圆心 cv2.circle(circle_img, (out_x, out_y), 3, (0, 255, 255), -1) # 记录外圆坐标 out_xpoint = out_x out_ypoint = out_y # 只框出单个针角的位置区域 step_center = 30 step_rect = 60 out_x -= step_center out_y -= step_center needleRect = image[out_y: out_y + step_rect, out_x: out_x + step_rect] # cv2.imshow("needleRect", needleRect) # 根据检测到的圆形连接器中心找针角位置 centerPoint = needelCenter_detect(needleRect) if len(centerPoint) == 0: print("调整位置") else: # 将针角的坐标原还至原图 in_x = int(centerPoint[0].pt[0]) in_y = int(centerPoint[0].pt[1]) in_x += out_x in_y += out_y # 画出针角的圆心 cv2.circle(circle_img, (in_x, in_y), 3, (0, 255, 0), -1) # 计算两者的距离 # 假设通过标定其一个像素代表0.0056mm DPI = 0.00568 dis = math.sqrt(math.pow(out_xpoint - in_x,2) + math.pow(out_ypoint - in_y,2)) print("两者相互之间的距离为(mm):", dis*DPI) cv2.imshow("image",circle_img) cv2.waitKey(1) if __name__ == "__main__": # # 测试0 如果是小图 需要将检测程序中的cv2.waitKey(1)修改为cv2.waitKey()不然看到图片 # image = cv2.imread("images/CircleLinker/CLinker01.jpg") # # cv2.imshow("show",image) # # cv2.waitKey() # roi = image # circle_detect(roi) # 测试1 从原图中换到连接器位置 image = cv2.imread("SingleImages/src/single.jpg") # cv2.imshow("show",image) # cv2.waitKey() # 如何准确找到圆形连接器 ---》用yolo训练后能准备找到 roi = image[1800:2300, 1800:2300 ] # cv2.imshow("show",roi) # cv2.waitKey() circle_detect(roi) # # 测试2 如果是小图 需要将检测程序中的cv2.waitKey(1)修改为cv2.waitKey()不然看到图片 # image = cv2.imread("SingleImages/single04.jpg") # # cv2.imshow("show",image) # # cv2.waitKey() # roi = image # circle_detect(roi) # # 测试3 检测文件夹下所有图片 # path = r"D:\BUFFER\Pycharm\ZhenJiaoDect\SingleImages" # for filename in os.listdir(path): # listdir的参数是文件夹的路径 # filenames = path + '\\' + filename # # print(filenames) # img_orig = cv2.imread(filenames, 1) # print(filenames) # # if img_orig is None: # print("Warning: No Pictures") # else: # circle_detect(img_orig) # # # 测试4 打开相机测试 # # 需要将检测程序中的cv2.waitKey()修改为cv2.waitKey(1) # # 否则看到不视频实时检测结果 # capture = cv2.VideoCapture(0) # # while (True): # # 获取一帧 # ret, frame = capture.read() # circle_detect(frame) # # # cv2.imshow('frame', frame) # # if cv2.waitKey(1) == ord('q'): # break
-
一、场景浏览器访问淘宝,再访问天猫,继续访问1688......此时,浏览器中的cookie是什么状态?显然,包含上述3个网站的所有cookie二、此时,若通过selenium get_cookies()方法,能获取到浏览器所有cookie吗?答案显然是不能的(webdriver安全考虑),此方法只能获取当前请求域名下的所有cookie故访问天猫或1688会登录失败。那可以通过什么方式,将浏览器所有cookie获取?方案一:基于浏览器内核,打造属于自己的浏览器,解除限制方案二:挂代理,Fiddler,mitmproxy等方案三:分别请求对应域名,获取所有cookie(推荐,笔者首创)三、样例代码12345678910lmdd_url = f'{self.root_lmdd_url}/seller/dashboard/plan/order' self.chrome.get(lmdd_url)cookie_list = self.chrome.get_cookies() self.chrome.get(self.root_lmdd_api_url)cookie_list_api = self.chrome.get_cookies() cookie_list.extend(cookie_list_api)self.update_session_cookie(cookie_list)补充:selenium通过add_cookie()添加cookieselenium通过add_cookie()添加cookie,再次访问网站时,服务器直接读取浏览器cookie第一次登陆 手动输入用户名密码12345678910111213141516# -*- coding:utf-8 -*-from selenium import webdriverfrom time import sleepdriver = webdriver.Firefox()driver.get('http://www.baidu.com')sleep(2)driver.find_element_by_xpath('//*[@id="u1"]/a[7]').click()driver.add_cookie({'name':'userName','value':'youname'})driver.add_cookie({'name':'password','value':'youpassword'})sleep(30)driver.get('http://www.baidu.com')driver.find_element_by_id('kw').send_keys('selenium')
-
前言 本文就介绍了Selenium的常用内容:了解Selenium Webdriver 是干什么的 以下是本篇文章正文内容,下面案例可供参考 一、Pip安装&创建Bowser对象 1.Pip install selenium pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple 2.创建Bowser对象 # 导入webdriver模块 from selenium import webdriver # 指定使用Chrome浏览器 driver = webdriver.Chrome() # chrome_options,executable_path常用这两个参数 二、webdriver.ChromeOptions配置 配置浏览器的常用模式 chromeoptions 的常用功能 (1)添加启动参数 (add_argument) (2)添加扩展应用参数 (add_extension, add_encoded_extension),常用在代理身份验证 (3)添加实验性质参数 (add_experimental_option) 代码如下(示例): options= webdriver.ChromeOptions() # 创建配置对象 options.add_argument('lang=zh_CN.UTF-8') # 设置中文 options.add_argument('--headless') # 无头参数,浏览器隐藏在后台运行 options.add_argument('--disable-gpu') # 禁用GPU加速 options.add_argument('--start-maximized')#浏览器最大化 options.add_argument('--window-size=1280x1024') # 设置浏览器分辨率(窗口大小) options.add_argument('--user-agent=""') # 设置请求头的User-Agent options.add_argument('--incognito') # 隐身模式(无痕模式) options.add_argument(f'--proxy-server={proxy}') # 添加IP代理 proxy=f"http://{ip}:{port}" # 关闭'Chrome目前受到自動測試軟體控制'的提示 options.add_experimental_option('useAutomationExtension', False) options.add_experimental_option('excludeSwitches', ['enable-automation']) prefs = { "download.default_directory":"D:\download", # 设置浏览器下载地址(绝对路径) "profile.managed_default_content_settings.images": 2, # 不加载图片 } chrome_options.add_experimental_option('prefs', prefs) # 添加prefs # chrome_options="浏览器配置参数", executable_path="浏览器驱动绝对路径" driver = webdriver.Chrome(chrome_options=options") # 创建浏览器对象 driver.maximize_window() # 浏览器窗口最大化 driver.set_page_load_timeout(30) # 设置连接超时30秒 三、常用代码 # 导入webdriver模块 from selenium import webdriver driver = webdriver.Chrome() # chrome_options,executable_path常用这两个参数 # get 会一直等到页面被完全加载,然后才会执行下一步代码,如果超出了set_page_load_timeout()的设置,则会抛出异常。 driver.get("https://baidu.com/") new_window = driver.window_handles[-1] # 新窗口'-1'代表打开的最后一个窗口,导航栏有多少个窗口根据下标来锁定 driver.switch_to.window(new_window) # 切换到新窗口: driver.switch_to.frame('passport_iframe') # 根据name或id 定位至 iframe driver.switch_to.default_content() # 切换出(iframe)至默认,有好多种切换方式找BaiDu driver.find_element_by_xpath('//input[@xx="xxxx"]').send_keys(content) # 根据xpath语法定位元素输入内容 driver.find_element_by_xpath('//div[@xx="xxxx"]').click() # 根据xpath语法定位元素后并点击 driver.find_element_by_xpath('//div[@xx="xxxx"]').text # 根据xpath语法定位后获取元素的文本信息 driver.get_cookie('name') #根据name取出对应字典类型的对象 driver.get_cookies() # 返回一个列表,包含多个字典类型的对象 # 添加Cookie部分参数介绍:name=cookie的名称,value=cookie对应的值,domain=服务器域名,expiry=Cookie有效终止日期 driver.add_cookie({'name' : 'xxx', 'value' : 'xxx'}) # 添加cookie driver.delete_cookie('name') # 删除指定部分的Cookie driver.delete_all_cookies() # 删除所有Cookie js="var q=document.documentElement.scrollTop=10000" # 滚动到最下面 js="var q=document.documentElement.scrollTop=0" # 滚动到最上面 driver.execute_script(js) # 执行JS代码,更多自行BaiDu driver.quit() # 退出浏览器 四、selenium的异常处理 # 导入exceptions模块 from selenium.common import exceptions try: # 执行代码 except exceptions.TimeoutException: print("xxxx - 请求加载超时异常!\n", end='') except exceptions.NoSuchElementException: print("xxxx - 网页元素定位异常!\n", end='') except exceptions.NoSuchWindowException: print("xxxx - 目标窗口切换异常!\n", end='') except exceptions.WebDriverException: print("xxxx - 浏览器对象各种异常!\n", end='') except Exception: print("xxxx - 以上未捕捉到的异常!\n", end='') selenium 更多异常参考:https://blog.csdn.net/cunhui1209/article/details/112544287 总结 例如:以上就是今天要记录的内容,本文仅仅简单介绍了selenium的使用,selenium 提供了大量能使我们捷地实现自动化测试的函数和方法,后续会在本文的基础上记录新的常用操作。 Google官方下载地址:https://www.google.cn/chrome/ Google驱动下载地址:https://npm.taobao.org/mirrors/chromedriver/ 驱动配置请参考:https://blog.csdn.net/flyskymood/article/details/123203105 ———————————————— 版权声明:本文为CSDN博主「EXI-小洲」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/EXIxiaozhou/article/details/127073705
-
Python 中的 Map 函数处理可迭代对象map()的这个第一个参数是一个转换函数。换句话说,它是将每个原始项转化为新的 (已转化) 项的函数。尽管 Python 文档中称这个参数为函数,但它可以是任何 Python 可调用的函数,这包括内置函数、类、方法、lambda 函数和用户定义的函数。本文中,我们将一起学习Python的 map() 如何工作;如何使用 map() 转换不同类型的 Python 迭代变量。有了这些知识,我们就能在程序中有效地使用map(),或者使用列表推导式或生成器表达式来使代码更加Pythonic。为了更好地理解map(),需要一些前置知识,如了解如何使用迭代器、for循环、函数和lambda函数的一些知识。可以查看我们日前详细介绍过的戳👉:Python 中的万能之王 Lambda 函数Python中的函数式编程在函数式编程中,计算是通过组合函数来完成的,这些函数接受参数并返回一个(或多个)具体数值作为结果。这些函数不修改其输入参数,也不改变程序的状态。它们只是提供一个特定的计算结果。这些类型的函数通常被称为纯函数。从理论上讲,使用函数式编程风格构建的程序将更易运行。开发,因为我们可以单独编码和使用每一个函数调试和测试,因为我们可以测试和调试个别功能,而不看程序的其他部分。理解,因为我们不需要处理整个程序的状态变化函数式编程通常使用列表、数组和其他可迭代的数据类型,以及一组对数据进行操作和转换的函数来表示。当涉及到用函数式处理数据时,至少有三种常用的技术。Mapping 包括对可迭代对象应用转换函数来生成新的可迭代对象。通过对原始可迭代对象中的每一项调用转换函数来生成新的可迭代对象中的项。Filtering 包括对可迭代对象应用谓词或布尔值函数来生成新的可迭代对象。新可迭代对象中的项是通过过滤掉原始可迭代对象中使谓词函数返回False的任何项来生成的。Reducing 括对可迭代对象应用reduce函数来产生单个累积值。早在1993年,Python社区就要求有一些函数式编程的特性,他们要求的是一个Lambda 匿名函数一个map()函数一个filter()函数一个reduce()函数由于一位社区成员的贡献,这些函数式特性被添加到语言中。现在,map()、filter()和reduce()是Python中函数式编程风格的基本组成部分。在本文中,我们将了解这些函数之一,即内置函数map()。我们还将学习如何使用列表推导式和生成器表达式,以Pythonic和可读的方式获得map()的相同功能。开始使用 map() 函数有时我们会面临这样的情况:需要对输入可迭代对象的所有项执行相同的操作来构建一个新的可迭代对象。解决这个问题的最快速、最常见的方法是使用一个 Python for 循环。然而也可以通过使用 map() 来解决这个问题,而不需要显式循环。在下面,我们将一起学习 map() 的工作原理,以及如何使用它来处理和转换迭代变量而不需要循环。入门 map()map()循环遍历输入可迭代对象(或可迭代对象)的项,并返回一个迭代器,该迭代器是对原始输入可迭代对象中的每个项应用转换函数得到的结果。根据 文档[1],map()接受一个函数对象和一个可迭代对象(或多个可迭代对象)作为参数,并返回一个迭代器,根据需要生成转换后的条目。函数签名定义如下:map(function, iterable[, iterable1, iterable2,..., iterableN] )map()将函数应用于循环中可迭代对象中的每个元素,并返回一个新的迭代器,按需生成转换后的元素。函数可以是任何Python函数,其参数的数量等于传递给 map() 的可迭代对象的数量。注意: map() 的第一个参数是一个函数对象,需要传递一个函数而不调用它。即不需要使用一对圆括号。map()的这个第一个参数是一个转换函数。换句话说,它是将每个原始项转化为新的 (已转化) 项的函数。尽管 Python 文档中称这个参数为函数,但它可以是任何 Python 可调用的函数,这包括内置函数、类、方法、lambda 函数和用户定义的函数。map()执行的操作通常被称为mapping,因为它将输入可迭代对象中的每一项映射到结果可迭代对象中的新项。为此,map()对输入的可迭代对象中的所有项应用一个转换函数。为了更好地理解map(),假设需要取一个数值列表,并将其转化为一个包含原列表中每个数字的平方值的列表。此时可以使用一个for循环,代码如下。>>> numbers = [1, 2, 3, 4, 5]>>> squared = []>>> for num in numbers:... squared.append(num ** 2)...>>> squared[1, 4, 9, 16, 25]当在 numbers上运行这个循环时,会得到一个平方值列表。for 循环遍历 numbers,并对每个值应用幂运算。最后,它将结果值存储在squared中。使用map()可以在不使用显式循环的情况下获得相同的结果。看看上面示例的以下重新实现:>>> def square(number):... return number ** 2...>>> numbers = [1, 2, 3, 4, 5]>>> squared = map(square, numbers)>>> list(squared)[1, 4, 9, 16, 25]square()是一个转换函数,将一个数字映射到它的平方值。调用map()将square()应用于numbers中的所有值,并返回一个生成平方值的迭代器。然后在map()上调用 list() 来创建一个包含平方值的列表对象。由于map()是用C语言编写的,并且是高度优化的,它的内部隐含循环可以比普通的Python for循环更有效率。这是使用map()的一个优点。map()的第二个优点与内存消耗有关。使用for循环时,需要将整个列表存储在系统的内存中。使用map(),可以按需获得项目,并且在给定的时间内只有一个项目在系统的内存中。注意: 在Python中2。X,map() 返回一个列表。此行为在Python 3.x中发生了改变。现在,map()返回一个map对象,这是一个迭代器,可生成按需的项目。这就是为什么我们需要调用 list() 来创建想要的列表对象。再比如,我们需要将一个列表中的所有项目从字符串转换为整数。要做到这一点,我们可以使用map()和int(),如下所示。>>> str_nums = ["4", "8", "6", "5", "3", "2", "8", "9", "2", "5"]>>> int_nums = map(int, str_nums)>>> int_nums>>> list(int_nums)[4, 8, 6, 5, 3, 2, 8, 9, 2, 5]>>> str_nums["4", "8", "6", "5", "3", "2", "8", "9", "2", "5"]map() 将 int() 应用于 str_nums 中的每个值。由于 map() 返回一个迭代器(一个map对象),需要调用 list(),这样我们就可以用完迭代器并将其变成一个list对象。注意,在这个过程中,原始序列不会被修改。在不同类型的函数中使用map()我们可以用 map() 来使用任何种类的Python可调用函数。唯一的条件是该可调用函数需要一个参数,并返回一个具体而有用的值。例如,我们可以使用类、实现了特殊方法 __call__()的实例、实例方法、类方法、静态方法以及函数。有一些内置的函数,我们可以和 map() 一起使用。请看下面的例子。>>> numbers = [-2, -1, 0, 1, 2]>>> abs_values = list(map(abs, numbers))>>> abs_values[2, 1, 0, 1, 2]>>> list(map(float, numbers))[-2.0, -1.0, 0.0, 1.0, 2.0]>>> words = ["Welcome", "to", "Real", "Python"]>>> list(map(len, words))[7, 2, 4, 6]我们可以用 map() 使用任何内置函数,只要该函数接受一个参数并返回一个值。在使用map()时,我们会看到一个常见的模式是使用一个lambda函数作为第一个参数。当我们需要向map()传递一个基于表达式的函数时,lambda函数就很方便。例如,我们可以用lambda函数重新实现平方值的例子,如下所示。>>> numbers = [1, 2, 3, 4, 5]>>> squared = map(lambda num: num ** 2, numbers)>>> list(squared)[1, 4, 9, 16, 25]在使用 map() 时,lambda函数是相当有用的。它们可以发挥 map() 的第一个参数的作用。我们可以在使用 map() 的同时使用lambda函数来快速处理和转换我们的迭代变量。用map()处理多个输入可迭代对象如果为map()提供了多个迭代变量,那么转换函数必须接受与传递的迭代变量同样多的参数。map()的每一次迭代将从每个迭代器中传递一个值作为参数给函数,迭代在最短的迭代器的末端停止。以下使用 pow() 的例子。>>> first_it = [1, 2, 3]>>> second_it = [4, 5, 6, 7]>>> list(map(pow, first_it, second_it))[1, 32, 729]pow() 接收两个参数,x和y,并返回x到y的幂。在第一次迭代中,x是1,y是4,结果是1。在第二次迭代中,x是2,y是5,结果是32,以此类推。最后的可迭代的长度只相当于最短的可迭代的长度,在这种情况下就是first_it。我们可以使用不同种类的数学运算来合并两个或多个数值迭代表。下面是一些使用lambda函数对几个输入迭代表进行不同数学运算的例子。>>> list(map(lambda x, y: x - y, [2, 4, 6], [1, 3, 5]))[1, 1, 1]>>> list(map(lambda x, y, z: x + y + z, [2, 4], [1, 3], [7, 8]))[10, 15]在第一个示例中,使用减法操作合并两个可迭代对象,每个可迭代对象包含三个元素。在第二个示例中,将三个可迭代对象的值相加。用map()转换字符串的可迭代对象当处理字符串对象的可迭代对象时,我们可以借助Python的map(),使用某种转换函数转换所有对象。下面我们通过一些示例,了解如何使用 map()转换字符串对象的可迭代对象。使用 str的方法处理字符串的一个很常见的方法是使用str类的一些方法将给定的字符串转换为一个新的字符串。如果我们正在处理字符串的迭代表,并且需要对每个字符串应用相同的转换,那么我们可以使用 map() 和各种字符串方法。>>> string_it = ["processing", "strings", "with", "map"]>>> list(map(str.capitalize, string_it))['Processing', 'Strings', 'With', 'Map']>>> list(map(str.upper, string_it))['PROCESSING', 'STRINGS', 'WITH', 'MAP']>>> list(map(str.lower, string_it))['processing', 'strings', 'with', 'map']使用map() 和str方法,可以对string_it 中的每一项执行一些转换。大多数时候,使用不带附加参数的方法,比如str.capitalize(), str.lower(), str.swapcase(), str.title(),以及str.upper()。我们也可以使用一些带有默认值的附加参数的方法,比如str.strip(),它需要一个叫做char的可选参数,默认为删除空白。>>> with_spaces = ["processing ", " strings", "with ", " map "]>>> list(map(str.strip, with_spaces))['processing', 'strings', 'with', 'map']当像这样使用 str.strip() 时,其实是传入默认值char。在这种情况下,我们使用 map() 来删除 with_spaces 项中的所有空白。注意: 如果需要提供参数而不是使用默认值,可以使用lambda函数。下面是一个使用 str.strip() 去除点而不是默认的空白的例子。>>> with_dots = ["processing..", "...strings", "with....", "..map.."]>>> list(map(lambda s: s.strip("."), with_dots))['processing', 'strings', 'with', 'map']lambda函数在字符串对象s上调用.strip(),删除所有前导和尾部的点。例如,当处理文本文件时,其中的行可能有尾部的空格(或其他字符),而需要删除它们时,这种技术就会很方便。如果是这种情况,那么需要考虑使用str.strip()而不使用自定义字符,也会删除换行字符。删除标点符号有时在处理文本时,需要删除将文本分割成单词后留下的标点符号。我们可以创建一个自定义函数,使用匹配最常见的标点符号的正则表达式来删除单个单词的标点符号。下面是使用sub()[2]实现该函数的可能方法,它是一个存在于Python标准库中的re[3]模块中的正则表达式函数:>>> import re>>> def remove_punctuation(word):... return re.sub(r'[!?.:;,"()-]', "", word)>>> remove_punctuation("...Python!")'Python'在自定义函数remove_punctuation()中,使用一个正则表达式模式来匹配在任何英文文本中发现的最常见的标点符号。对re.sub()的调用使用一个空字符串("")替换了匹配的标点符号,并返回一个干净的单词。有了转换函数,我们可以使用map()对文本中的每个字进行转换。下面是它的工作原理。>>> text = """Some people, when confronted with a problem, think... "I know, I'll use regular expressions."... Now they have two problems. Jamie Zawinski""">>> words = text.split()>>> words['Some', 'people,', 'when', 'confronted', 'with', 'a', 'problem,', 'think', '"I', 'know,', "I'll", 'use', 'regular', 'expressions."', 'Now', 'they', 'have', 'two', 'problems.', 'Jamie', 'Zawinski']>>> list(map(remove_punctuation, words))['Some', 'people', 'when', 'confronted', 'with', 'a', 'problem', 'think','I', 'know', "I'll", 'use', 'regular', 'expressions', 'Now', 'they', 'have', 'two', 'problems', 'Jamie', 'Zawinski']在这段文字中,有些词包括标点符号。例如,我们有 'people,'而不是 'people','problem,'不是 'problem',等等。对map()的调用将remove_punctuation()应用于每个词,并删除任何标点符号。因此,第二个列表中存储的是处理后的干净的单词。注意我们的正则表达式中没有撇号('),因为我们想将像I'll这样的缩略语保持原貌。实现凯撒密码算法罗马政治家Julius Caesar曾经用密码来保护他发给他的将军们的信息,用密码来加密。Caesar cipher 凯撒密码[4]将每个字母移位若干个字母。例如,如果我们将字母a移位三个,那么我们就会得到字母d,以此类推。如果移位超过了字母表的末端,那么我们只需要旋转回字母表的开头。在旋转3的情况下,x会变成a。以下是旋转后字母表的样子。原文字母: abcdefghijklmnopqrstuvwxyz字母表旋转3: defghijklmnopqrstuvwxyzabc下面的代码实现了rotate_chr(),这个函数接收一个字符并将其旋转3圈。rotate_chr()将返回旋转后的字符。下面是代码。def rotate_chr(c): rot_by = 3 c = c.lower() alphabet = "abcdefghijklmnopqrstuvwxyz" # 保留标点符号和空白处 if c not in alphabet: return c rotated_pos = ord(c) + rot_by # 如果旋转的位置在字母表内 if rotated_pos <= ord(alphabet[-1]): return chr(rotated_pos) # 如果旋转超出了字母表的范围 return chr(rotated_pos - len(alphabet))在rotate_chr()中,首先检查该字符是否在字母表中。如果不是,那么就返回相同的字符。这样做的目的是为了保留标点符号和其他不寻常的字符。在第8行,计算该字符在字母表中的新的旋转位置,这里要使用内置函数ord()[5]。ord()接收一个Unicode字符,并返回一个整数,代表输入字符的 Unicode码位。例如,ord("a")返回97,而ord("b")返回98。>>> ord("a")97>>> ord("b")98ord() 接收一个字符作为参数,并返回输入字符的Unicode码位。如果把这个整数加到rot_by的目标数上,那么将得到新字母在字母表中的旋转位置。在这个例子中,rot_by是3。因此,字母 "a" 旋转3下将成为位置100的字母,也就是字母 "d"。字母 "b" 旋转三下将成为位置101的字母,也就是字母 "e",以此类推。如果字母的新位置不超过最后一个字母的位置(alphabet[-1]),那么就返回这个新位置的字母,此时可以使用内置函数chr()。chr()是ord()的逆运算。它接收一个代表Unicode字符的Unicode码位的整数,并返回该位置的字符。例如,chr(97)将返回'a',而chr(98)将返回'b'。>>> chr(97)'a'>>> chr(98)'b'chr()接收一个整数,代表一个字符的Unicode码位,并返回相应的字符。最后,如果新的旋转位置超出了最后一个字母的位置(alphabet[-1]),那么需要旋转回到字母表的开头,此时需要从旋转的位置减去字母表的长度(rotated_pos - len(alphabet)),然后用chr()返回这个新位置的字母。用rotate_chr()作为转换函数,可以用map()用凯撒密码算法对任何文本进行加密。下面是一个使用str.join()来连接字符串的例子。>>> "".join(map(rotate_chr, "My secret message goes here."))'pb vhfuhw phvvdjh jrhv khuh。字符串在Python中也是可迭代的。因此,对map()的调用将rotate_chr()应用于原始输入字符串中的每个字符。在这种情况下,"M" 变成 "p","y" 变成 "b",等等。最后,对str.join()的调用将每个旋转的字符连接到一个最终的加密信息中。用map()转换数字的可迭代对象map()在处理和转换数字值的迭代表方面也有很大潜力。可以进行各种各样的数学和算术运算,将字符串值转换成浮点数或整数,等等。在下面的内容中,我们将一起学习一些如何使用map()来处理和转换数字迭代表的例子。使用数学运算使用数学运算来转换数值迭代的一个常见例子是使用幂运算符(**)。在下面的例子中,我们编写了一个转换函数,它接收一个数字并返回数字的平方和立方。>>> string_it = ["processing", "strings", "with", "map"]>>> list(map(str.capitalize, string_it))['Processing', 'Strings', 'With', 'Map']>>> list(map(str.upper, string_it))['PROCESSING', 'STRINGS', 'WITH', 'MAP']>>> list(map(str.lower, string_it))['processing', 'strings', 'with', 'map']powers()接受一个数字'x'并返回它的平方和立方。由于Python将多个返回值作为元组处理,所以每次调用powers()都会返回一个有两个值的元组。当你用 powers() 作为参数调用 map()时,你会得到一个包含输入可迭代对象中每个数字的平方和立方的元组列表。使用 map() 可以执行许多与数学相关的转换。您可以在每个值上添加常量或从它们中减去常量。您还可以使用 math 模块中的一些函数,如sqrt() , factorial() , sin(),cos() ,等等。下面是一个使用 factorial() 的例子:>>> import math>>> numbers = [1, 2, 3, 4, 5, 6, 7]>>> list(map(math.factorial, numbers))[1, 2, 6, 24, 120, 720, 5040]在这种情况下,我们将数字转化为一个新的列表,包含原列表中每个数字的阶乘。我们可以使用'map()对数字可迭代对象执行广泛的数学转换。你深入到这个话题的程度取决于你的需求和你的想象力。考虑一下这个问题,编写我们自己的示例代码!转换温度·的另一个用例是在测量单位之间进行转换。假设我们有一个以摄氏度或华氏度测量的温度列表,我们需要将它们转换为相应的华氏度或摄氏度的温度。可以编码两个转换函数来完成这个任务。def to_fahrenheit(c): return 9 / 5 * c + 32def to_celsius(f): return (f - 32) * 5 / 9to_fahrenheit() 接收摄氏温度测量值,并将其转换为华氏温度。类似地,to_celsius()接收华氏温度并将其转换为摄氏温度。这些函数可以作为转换函数使用,即可以将它们与map()一起使用,将温度测量值的可迭代数据分别转换为华氏和摄氏。>>> celsius_temps = [100, 40, 80] 。>>> # 转换为华氏温度>>> list(map(to_fahrenheit, celsius_temps))[212.0, 104.0, 176.0]>>> fahr_temps = [212, 104, 176] 。>>> # 转换为摄氏度>>> list(map(to_celsius, fahr_temps))[100.0, 40.0, 80.0]如果用to_fahrenheit()和celsius_temps调用map(),那么会得到一个华氏温度测量值的列表。如果用to_celsius()和fahr_temps来调用map(),那么会得到一个以摄氏度为单位的温度测量列表。要扩展这个例子并涵盖任何其他种类的单位转换,只需要编码一个适当的转换函数。将字符串转换为数字在处理数字数据时,我们可能会遇到所有数据都是字符串值的情况。要做任何进一步的计算,我们需要将字符串值转换成数字值。map()也可以帮助处理这些情况。如果我们确定我们的数据是干净的,不包含错误的值,那么我们可以根据我们的需要直接使用float()或int()。下面是一些例子。>>> # 转换为浮点>>> list(map(float, ["12.3", "3.3", "-15.2"])[12.3, 3.3, -15.2]>>> # 转换为整数>>> list(map(int, ["12", "3", "-15"]))[12, 3, -15]在第一个例子中,使用float()与map()将所有的值从字符串值转换为浮点值。在第二个例子中,使用int()将字符串转换为整数。注意,如果其中一个值不是一个有效的数字,那么会得到一个ValueError。如果我们不确定数据是否干净,那么可以使用一个更精细的转换函数,如下面的。>>> def to_float(number):... try:... return float(number.replace(",", "."))... except ValueError:... return float("nan")...>>> list(map(to_float, ["12.3", "3,3", "-15.2", "One"]))[12.3, 3.3, -15.2, nan]在to_float()中,使用try语句,在转换number 时,如果 float() 失败,则捕获 ValueError 。如果没有发生错误,那么函数将返回转换为有效浮点数的number 。否则,将得到nan (非数值) 值,这是一个特殊的 float 值,可以使用它来表示不是有效数字的值,就像上面示例中的 "One" 一样。我们可以根据需要定制 to_float()。例如,我们可以用 return 0.0 语句代替 return float("nan") 语句,等等文章来源:cid:link_0
-
Python运算符与表达式 Python运算符包括赋值运算符、算术运算符、关系运算符、逻辑运算符、位运算符、成员运算符和身份运算符。表达式是将不同类型的数据 (常亮、变量、函数)用运算符按照一定得规则连接起来的式子。 算术运算符包括四则运算符、求模预算符和幂运算符。 本章详细介绍了各种运算符的使用方法和表达式规则 算术运算符和算术表达式 算术运算符可以对算术运算对象进行算术运算,常见的运算符有 +:使两个对象相加 -:得到复数或者数字的相减的 *:两个数相乘或一个字符串被重复若干次 /:x除以y %:取余返回余数 //:取整返回整数部分 **:求次幂 由算术运算符与算术运算对象组成的式子称为算术运算表达式 范例:求自然数268的逆序数并输出 x = 268 a = x // 100 #计算百位数字. b = x // 10 % 10 #计算十位数字. c = x % 10 #计算个位数字. y = c * 100 + b * 10 + a #计算逆序自然数. print("原自然数: x =",x) print("逆序自然数: y =",y) 输出结果: 原自然数: x = 268 逆序自然数: y = 862 关系运算符和关系运算表达式 关系运算符通常是为了比较对象之间的关系,对象可以是数值或者字符串等常量、变量或表达式。 类属于a=b形式,由对象和关系运算符组成的表达式称为关系运算表达式。 关系表达式的运算结果只有两种,结果为真则返回True ,结果为假则返回False。 范例:关系运算符的使用 >>> 3 >= 2 True >>> 3 > 1 > 2 #等价于3 > 1 and 1 > 2. False >>> 3 != 2 True 同其他语言不同,在python中3>1>2合法,这里等价于3>1 and 1>2,似乎相比其他语言更加人性化 赋值运算符和赋值运算表达式 赋值运算符用来将表达式的结果赋值给变量 由赋值运算符与赋值运算对象组成的式子称为赋值运算表达式。 范例:赋值运算符和赋值运算表达式的使用 a = b = c = 100 s = 0 s += a s += b s += c print("s =",s) 运行结果: s = 300 在内存中会给100分配块空间,而a,b,c三个变量就像指针一样可以同时指向这块空间 逻辑运算符和逻辑运算表达式 逻辑运算符用来判断逻辑运算对象之间的关系 由逻辑运算符与逻辑运算对象组成的式子称为逻辑运算表达式。 运算符 名称 逻辑表达式 描述 and 逻辑与 x and y x为True或非0,返回y;否则返回x or 逻辑或 x or y x为True或非0,返回x,否则返回y not 逻辑非 not x x为True或非0,返回False,否则返回True 范例:逻辑运算符的使用 >>> True and True True >>> True and 3 3 >>> 0 and True 0 >>> 0 and 3 0 >>> False or True True >>> False or 4 4 >>> 3 or True 3 >>> 3 or 4 3 >>> not True False >>> not 3 False 解释 and前为真,返回and后的对象 or前为真,返回or前对象 not下对象为真则返回False,否则返回True 位运算符和位运算表达式 位运算符用来把两个运算对象按照二进制进行位运算。 由位运算符与位运算对象组成的式子称为位运算表达式。 这里可能不好理解的就算a<<2,输出240(11110000),这里a原本的值为60(00111100),当左移两位时右边不够用0补齐于是输出便是240 范例:使用^运算符对字符加密和解密 key = input("请输入加密密钥: ") enc = input("请输入要加密的字符: ") dec = ord(key) ^ ord(enc) #对字符加密. print("加密结果:",chr(dec)) enc = ord(key) ^ dec #对字符解密. print("解密结果:",chr(enc)) 运行结果: 请输入加密密钥: 6 请输入要加密的字符: a 加密结果: W 解密结果: a 这里是通过ord()函数将key,enc转换为unicode码,通过chr()函数将加密后的编码转化为字符 成员运算符和成员运算表达式 成员运算符用来判断两个对象之间的关系。由成员运算符与成员运算对象组成的式子称为成员运算表达式。 范例:成员运算符的使用 元曲四大家 = ["关汉卿"," 白朴"," 郑光祖","马致远"] if "汤显祖" in 元曲四大家: print("'汤显祖'是元曲四大家之一.") else: print("'汤显祖'不是元曲四大家之一.") 运行结果: '汤显祖'不是元曲四大家之一. 身份运算符和身份运算表达式 身份运算符用来比较两个对象之间的存储单元。 由身份运算符与身份运算对象组成的式子称为身份运算表达式。 3种比较方法: (1) a == b:比较对象a和对象b的值是否相等。 (2) a is b:比较对象a和对象b是否有相同的引用,即id是否相等。 (3) operator.eq(a, b)函数:比较对象a和对象b是否有相同的值。 范例:比较两个整型变量 import operator a = 20 b = 20 print("a is b ?",a is b) print("a == b ?",a == b) print("operator.eq(a,b) ?",operator.eq(a,b)) 运行结果: a is b ? True a == b ? True operator.eq(a,b) ? True 范例:比较两个列表对象 import operator x = [1,4,8] y = [1,4,8] print("x is y ?",x is y) print("x == y ?",x == y) print("operator.eq(x,y)?",operator.eq(x,y)) 运行结果: x is y ? False x == y ? True operator.eq(x,y)? True 运算符的优先级 范例:使用运算符计算表达式 1. a = 10; b = 20; c = 30; d = 40 2. e = a + b * c / d 3. print("e =",e) 4. f = (a + b) * c / d 5. print("f =",f) 运行结果: e = 25.0 f = 22.5 ++i和--i的使用 补充说明: Python中的一些运算符不仅可用于数字等运算,还可以用于对字符串、列表和元组等组合对象的运算(如:*,+)。 Python支持++i、–i运算符,但含义和其他语言中的不同。 Python不支持i++、i–运算符。 范例:++和–的使用 >>> i = 2 >>> ++i #等价于+(+i) 2 >>> --i #等价于-(-i) 2 >>> 2--3 #等价于2-(-3)
-
一、Unittest用例的执行流程TestRunner的工作流程:遍历测试类中的测试用例,调用用例对象的run方法将测试用例的结果保存到TestResult中1、单线程执行测试用例特别注意:如果测试粒度按照文件为单位,那么文件中的测试类执行顺序就能得到保证如果测试粒度按照测试类为单位,那么测试类中的测试用例执行顺序就能得到保证如果测试粒度按照测试用例为单位,并且用例与用例之间有关联,那么测试用例执行顺序得不到保证import unittestfrom unittest import TestCase,TestSuite,TestLoader,TestResult'''粒度——》测试文件粒度——》测试类粒度——》用例级别'''from concurrent.futures.thread import ThreadPoolExecutor#todo 加载用例到测试套件中suite=unittest.defaultTestLoader.discover(r'D:\project_development\测试开发\day11\testcases')print('-------------------------单线程执行--------------------------------------')#todo 创建一个测试结果记录器result=unittest.TestResult()#todo 执行测试套件suite.run(result)print(suite)print('用例执行的结果,',result)二、测试套件的结构1、目录如下:2、测试文件test_demo1.pyimport timeimport unittestfrom ddt import ddt,data@ddtclass DemoA1(unittest.TestCase):@data(1,2,3,6)def test_demoa1(self,item):time.sleep(1)print('---------test_demoa1--------',item)@ddtclass DemoA2(unittest.TestCase):@data(1,2,3,6)def test_demoa2(self,item):time.sleep(1)print('---------test_demoa2--------',item)test_demo2.pyimport timeimport unittestfrom ddt import ddt,data@ddtclass DemoB1(unittest.TestCase):@data(1,2,3,6)def test_demob1(self,item):time.sleep(1)print('---------test_demob1--------',item)@ddtclass DemoB2(unittest.TestCase):@data(1,2,3,6)def test_demob2(self,item):time.sleep(1)print('---------test_demob1--------',item)test_demo3.pytest_demo4.py3、代码调试截图三、测试套件的结构1、将测试套件拆分为模块级别特别注意套件可以直接执行,套件中有run方法model_suite=[m for m in suite]result=unittest.TestResult()创建一个线程池对象,一共创建了4个模块,所以max_workers最大为4with ThreadPoolExecutor(max_workers=4) as tp: #创建一个线程池对象for i in model_suite:#i.run(result)tp.submit(i.run,result)2、将测试套件拆分为类级别class_suite=[]for m in suite:for c in m:class_suite.append(c)result=unittest.TestResult()with ThreadPoolExecutor(max_workers=8) as tp:for i in class_suite:tp.submit(i.run,result)3、将测试套件拆分为用例级别case_list=[]for m in suite:for c in m:for i in c:case_list.append(i)result=unittest.TestResult()with ThreadPoolExecutor(max_workers=32) as tp:for i in case_list:tp.submit(i.run,result)四、封装一个可以并发运行unittest测试用例的函数,参数接收两个参数,一个suite(测试套件)和mode(任务粒度:),根据传入的参数model,来对测试套件进行任务拆分,进行并发执行import unittestfrom unittest import TestCase,TestSuite,TestLoader,TestResult'''粒度——》用例级别粒度——》测试类'''from concurrent.futures.thread import ThreadPoolExecutor#todo 加载用例到测试套件中suite=unittest.defaultTestLoader.discover(r'D:\project_development\测试开发\day11\testcases')print('-------------------------多线程执行--------------------------------------')def run_cases(suite,model):#判断任务执行粒度task_list = []if model=='case':for m in suite:for c in m:for i in c:task_list.append(i)elif model=='cls':for m in suite:for c in m:task_list.append(c)else:task_list=[i for i in suite]result=unittest.TestResult()with ThreadPoolExecutor(max_workers=8) as tp:for i in task_list:tp.submit(i.run,result)run_cases(suite,'asd')————————————————版权声明:本文为CSDN博主「YZL40514131」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/YZL40514131/article/details/126982705
-
当前pip的源最新还是在2022年9月初,请更新下最新的源,谢谢~
-
用300行Python代码实现一个人脸识别系统 最近又多了不少朋友关注,先在这里谢谢大家。关注我的朋友大多数都是大学生,而且我简单看了一下,低年级的大学生居多,大多数都是为了完成课程设计,作为一个过来人,还是希望大家平时能多抽出点时间学习一下,这种临时抱佛脚的策略要少用嗷。今天我们来python实现一个人脸识别系统,主要是借助了dlib这个库,相当于我们直接调用现成的库来进行人脸识别,就省去了之前教程中的数据收集和模型训练的步骤了。 B站视频:用300行代码实现人脸识别系统_哔哩哔哩_bilibili CSDN博客:用300行Python代码实现一个人脸识别系统_dejahu的博客-CSDN博客 码云地址:face_dlib_py37_42: 用300行代码开发一个人脸识别系统-42 (gitee.com) 预编译dlib库下载地址:人脸识别系统+windows64位-dlib-19.17.0-cp37-cp37m-win_amd64.zip-深度学习文档类资源-CSDN文库 注:直接安装dlib库可能会有编译错误,可以通过下列方式获取编译好的dlib库 获取方式1: 直接从付费资源下载 人脸识别系统+windows64位-dlib-19.17.0-cp37-cp37m-win_amd64.zip-深度学习文档类资源-CSDN文库 获取方式2: 在B站视频三连并在评论区留下你的邮箱地址 用300行代码实现人脸识别系统_哔哩哔哩_bilibili 获取方式3: 在CSDN博客中三连并在评论区留下你的邮箱地址 用300行Python代码实现一个人脸识别系统_dejahu的博客-CSDN博客 基本原理 人脸识别和目标检测这些还不太一样,比如大家传统的训练一个目标检测模型,你只有对这个目标训练了之后,你的模型才能找到这样的目标,比如你的目标检测模型如果是检测植物的,那显然就不能检测动物。但是人脸识别就不一样,以你的手机为例,你发现你只录入了一次你的人脸信息,不需要训练,他就能准确的识别你,这里识别的原理是通过人脸识别的模型提取你脸部的特征向量,然后将实时检测到的你的人脸同数据库中保存的人脸进行比对,如果相似度超过一定的阈值之后,就认为比对成功。不过我这里说的只是简化版本的人脸识别,现在手机和门禁这些要复杂和安全的多,也不是简单平面上的人脸识别。 总结下来可以分为下面的步骤: 上传人脸到数据库 人脸检测 数据库比对并返回结果 这里我做了一个简答的示意图,可以帮助大家简单理解一下。 代码实现 废话不多说,这里就是我们的代码实现,代码我已经上传到码云,大家直接下载就行,地址就在博客开头。 不会安装python环境的兄弟请看这里:如何在pycharm中配置anaconda的虚拟环境_dejahu的博客-CSDN博客_如何在pycharm中配置anaconda 创建虚拟环境 创建虚拟环境前请大家先下载博客开头的码云源码到本地。 本次我们需要使用到python3.7的虚拟环境,命令如下: conda create -n face python==3.7.3 conda activate face 1 2 安装必要的库 pip install -r requirements.txt 1 愉快地开始你的人脸识别吧! 执行下面的主文件即可 python UI.py 1 或者在pycharm中按照下面的方式直接运行即可 首先将你需要识别的人脸上传到数据库中 通过第二个视频检测功能识别实时的人脸 详细的代码如下: # -*- coding: utf-8 -*- """ ------------------------------------------------- Project Name: yolov5-jungong File Name: window.py.py Author: chenming Create Date: 2021/11/8 Description:图形化界面,可以检测摄像头、视频和图片文件 ------------------------------------------------- """ # 应该在界面启动的时候就将模型加载出来,设置tmp的目录来放中间的处理结果 import shutil import PyQt5.QtCore from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * import threading import argparse import os import sys from pathlib import Path import cv2 import torch import torch.backends.cudnn as cudnn import os.path as osp FILE = Path(__file__).resolve() ROOT = FILE.parents[0] # YOLOv5 root directory if str(ROOT) not in sys.path: sys.path.append(str(ROOT)) # add ROOT to PATH ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative from models.common import DetectMultiBackend from utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams from utils.general import (LOGGER, check_file, check_img_size, check_imshow, check_requirements, colorstr, increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh) from utils.plots import Annotator, colors, save_one_box from utils.torch_utils import select_device, time_sync # 添加一个关于界面 # 窗口主类 class MainWindow(QTabWidget): # 基本配置不动,然后只动第三个界面 def __init__(self): # 初始化界面 super().__init__() self.setWindowTitle('Target detection system') self.resize(1200, 800) self.setWindowIcon(QIcon("images/UI/lufei.png")) # 图片读取进程 self.output_size = 480 self.img2predict = "" self.device = 'cpu' # # 初始化视频读取线程 self.vid_source = '0' # 初始设置为摄像头 self.stopEvent = threading.Event() self.webcam = True self.stopEvent.clear() self.model = self.model_load(weights="runs/train/exp_yolov5s/weights/best.pt", device="cpu") # todo 指明模型加载的位置的设备 self.initUI() self.reset_vid() ''' ***模型初始化*** ''' @torch.no_grad() def model_load(self, weights="", # model.pt path(s) device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu half=False, # use FP16 half-precision inference dnn=False, # use OpenCV DNN for ONNX inference ): device = select_device(device) half &= device.type != 'cpu' # half precision only supported on CUDA device = select_device(device) model = DetectMultiBackend(weights, device=device, dnn=dnn) stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx # Half half &= pt and device.type != 'cpu' # half precision only supported by PyTorch on CUDA if pt: model.model.half() if half else model.model.float() print("模型加载完成!") return model ''' ***界面初始化*** ''' def initUI(self): # 图片检测子界面 font_title = QFont('楷体', 16) font_main = QFont('楷体', 14) # 图片识别界面, 两个按钮,上传图片和显示结果 img_detection_widget = QWidget() img_detection_layout = QVBoxLayout() img_detection_title = QLabel("图片识别功能") img_detection_title.setFont(font_title) mid_img_widget = QWidget() mid_img_layout = QHBoxLayout() self.left_img = QLabel() self.right_img = QLabel() self.left_img.setPixmap(QPixmap("images/UI/up.jpeg")) self.right_img.setPixmap(QPixmap("images/UI/right.jpeg")) self.left_img.setAlignment(Qt.AlignCenter) self.right_img.setAlignment(Qt.AlignCenter) mid_img_layout.addWidget(self.left_img) mid_img_layout.addStretch(0) mid_img_layout.addWidget(self.right_img) mid_img_widget.setLayout(mid_img_layout) up_img_button = QPushButton("上传图片") det_img_button = QPushButton("开始检测") up_img_button.clicked.connect(self.upload_img) det_img_button.clicked.connect(self.detect_img) up_img_button.setFont(font_main) det_img_button.setFont(font_main) up_img_button.setStyleSheet("QPushButton{color:white}" "QPushButton:hover{background-color: rgb(2,110,180);}" "QPushButton{background-color:rgb(48,124,208)}" "QPushButton{border:2px}" "QPushButton{border-radius:5px}" "QPushButton{padding:5px 5px}" "QPushButton{margin:5px 5px}") det_img_button.setStyleSheet("QPushButton{color:white}" "QPushButton:hover{background-color: rgb(2,110,180);}" "QPushButton{background-color:rgb(48,124,208)}" "QPushButton{border:2px}" "QPushButton{border-radius:5px}" "QPushButton{padding:5px 5px}" "QPushButton{margin:5px 5px}") img_detection_layout.addWidget(img_detection_title, alignment=Qt.AlignCenter) img_detection_layout.addWidget(mid_img_widget, alignment=Qt.AlignCenter) img_detection_layout.addWidget(up_img_button) img_detection_layout.addWidget(det_img_button) img_detection_widget.setLayout(img_detection_layout) # todo 视频识别界面 # 视频识别界面的逻辑比较简单,基本就从上到下的逻辑 vid_detection_widget = QWidget() vid_detection_layout = QVBoxLayout() vid_title = QLabel("视频检测功能") vid_title.setFont(font_title) self.vid_img = QLabel() self.vid_img.setPixmap(QPixmap("images/UI/up.jpeg")) vid_title.setAlignment(Qt.AlignCenter) self.vid_img.setAlignment(Qt.AlignCenter) self.webcam_detection_btn = QPushButton("摄像头实时监测") self.mp4_detection_btn = QPushButton("视频文件检测") self.vid_stop_btn = QPushButton("停止检测") self.webcam_detection_btn.setFont(font_main) self.mp4_detection_btn.setFont(font_main) self.vid_stop_btn.setFont(font_main) self.webcam_detection_btn.setStyleSheet("QPushButton{color:white}" "QPushButton:hover{background-color: rgb(2,110,180);}" "QPushButton{background-color:rgb(48,124,208)}" "QPushButton{border:2px}" "QPushButton{border-radius:5px}" "QPushButton{padding:5px 5px}" "QPushButton{margin:5px 5px}") self.mp4_detection_btn.setStyleSheet("QPushButton{color:white}" "QPushButton:hover{background-color: rgb(2,110,180);}" "QPushButton{background-color:rgb(48,124,208)}" "QPushButton{border:2px}" "QPushButton{border-radius:5px}" "QPushButton{padding:5px 5px}" "QPushButton{margin:5px 5px}") self.vid_stop_btn.setStyleSheet("QPushButton{color:white}" "QPushButton:hover{background-color: rgb(2,110,180);}" "QPushButton{background-color:rgb(48,124,208)}" "QPushButton{border:2px}" "QPushButton{border-radius:5px}" "QPushButton{padding:5px 5px}" "QPushButton{margin:5px 5px}") self.webcam_detection_btn.clicked.connect(self.open_cam) self.mp4_detection_btn.clicked.connect(self.open_mp4) self.vid_stop_btn.clicked.connect(self.close_vid) # 添加组件到布局上 vid_detection_layout.addWidget(vid_title) vid_detection_layout.addWidget(self.vid_img) vid_detection_layout.addWidget(self.webcam_detection_btn) vid_detection_layout.addWidget(self.mp4_detection_btn) vid_detection_layout.addWidget(self.vid_stop_btn) vid_detection_widget.setLayout(vid_detection_layout) # todo 关于界面 about_widget = QWidget() about_layout = QVBoxLayout() about_title = QLabel('欢迎使用目标检测系统\n\n 提供付费指导:有需要的好兄弟加下面的QQ即可') # todo 修改欢迎词语 about_title.setFont(QFont('楷体', 18)) about_title.setAlignment(Qt.AlignCenter) about_img = QLabel() about_img.setPixmap(QPixmap('images/UI/qq.png')) about_img.setAlignment(Qt.AlignCenter) # label4.setText("如何调整学习率") label_super = QLabel() # todo 更换作者信息 label_super.setText("或者你可以在这里找到我-->肆十二") label_super.setFont(QFont('楷体', 16)) label_super.setOpenExternalLinks(True) # label_super.setOpenExternalLinks(True) label_super.setAlignment(Qt.AlignRight) about_layout.addWidget(about_title) about_layout.addStretch() about_layout.addWidget(about_img) about_layout.addStretch() about_layout.addWidget(label_super) about_widget.setLayout(about_layout) self.left_img.setAlignment(Qt.AlignCenter) self.addTab(img_detection_widget, '图片检测') self.addTab(vid_detection_widget, '视频检测') self.addTab(about_widget, '联系我') self.setTabIcon(0, QIcon('images/UI/lufei.png')) self.setTabIcon(1, QIcon('images/UI/lufei.png')) self.setTabIcon(2, QIcon('images/UI/lufei.png')) ''' ***上传图片*** ''' def upload_img(self): # 选择录像文件进行读取 fileName, fileType = QFileDialog.getOpenFileName(self, 'Choose file', '', '*.jpg *.png *.tif *.jpeg') if fileName: suffix = fileName.split(".")[-1] save_path = osp.join("images/tmp", "tmp_upload." + suffix) shutil.copy(fileName, save_path) # 应该调整一下图片的大小,然后统一防在一起 im0 = cv2.imread(save_path) resize_scale = self.output_size / im0.shape[0] im0 = cv2.resize(im0, (0, 0), fx=resize_scale, fy=resize_scale) cv2.imwrite("images/tmp/upload_show_result.jpg", im0) # self.right_img.setPixmap(QPixmap("images/tmp/single_result.jpg")) self.img2predict = fileName self.left_img.setPixmap(QPixmap("images/tmp/upload_show_result.jpg")) # todo 上传图片之后右侧的图片重置, self.right_img.setPixmap(QPixmap("images/UI/right.jpeg")) ''' ***检测图片*** ''' def detect_img(self): model = self.model output_size = self.output_size source = self.img2predict # file/dir/URL/glob, 0 for webcam imgsz = 640 # inference size (pixels) conf_thres = 0.25 # confidence threshold iou_thres = 0.45 # NMS IOU threshold max_det = 1000 # maximum detections per image device = self.device # cuda device, i.e. 0 or 0,1,2,3 or cpu view_img = False # show results save_txt = False # save results to *.txt save_conf = False # save confidences in --save-txt labels save_crop = False # save cropped prediction boxes nosave = False # do not save images/videos classes = None # filter by class: --class 0, or --class 0 2 3 agnostic_nms = False # class-agnostic NMS augment = False # ugmented inference visualize = False # visualize features line_thickness = 3 # bounding box thickness (pixels) hide_labels = False # hide labels hide_conf = False # hide confidences half = False # use FP16 half-precision inference dnn = False # use OpenCV DNN for ONNX inference print(source) if source == "": QMessageBox.warning(self, "请上传", "请先上传图片再进行检测") else: source = str(source) device = select_device(self.device) webcam = False stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx imgsz = check_img_size(imgsz, s=stride) # check image size save_img = not nosave and not source.endswith('.txt') # save inference images # Dataloader if webcam: view_img = check_imshow() cudnn.benchmark = True # set True to speed up constant image size inference dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt and not jit) bs = len(dataset) # batch_size else: dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt and not jit) bs = 1 # batch_size vid_path, vid_writer = [None] * bs, [None] * bs # Run inference if pt and device.type != 'cpu': model(torch.zeros(1, 3, *imgsz).to(device).type_as(next(model.model.parameters()))) # warmup dt, seen = [0.0, 0.0, 0.0], 0 for path, im, im0s, vid_cap, s in dataset: t1 = time_sync() im = torch.from_numpy(im).to(device) im = im.half() if half else im.float() # uint8 to fp16/32 im /= 255 # 0 - 255 to 0.0 - 1.0 if len(im.shape) == 3: im = im[None] # expand for batch dim t2 = time_sync() dt[0] += t2 - t1 # Inference # visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False pred = model(im, augment=augment, visualize=visualize) t3 = time_sync() dt[1] += t3 - t2 # NMS pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) dt[2] += time_sync() - t3 # Second-stage classifier (optional) # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) # Process predictions for i, det in enumerate(pred): # per image seen += 1 if webcam: # batch_size >= 1 p, im0, frame = path[i], im0s[i].copy(), dataset.count s += f'{i}: ' else: p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) p = Path(p) # to Path s += '%gx%g ' % im.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) if len(det): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round() # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string # Write results for *xyxy, conf, cls in reversed(det): if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view( -1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format # with open(txt_path + '.txt', 'a') as f: # f.write(('%g ' * len(line)).rstrip() % line + '\n') if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') annotator.box_label(xyxy, label, color=colors(c, True)) # if save_crop: # save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', # BGR=True) # Print time (inference-only) LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)') # Stream results im0 = annotator.result() # if view_img: # cv2.imshow(str(p), im0) # cv2.waitKey(1) # 1 millisecond # Save results (image with detections) resize_scale = output_size / im0.shape[0] im0 = cv2.resize(im0, (0, 0), fx=resize_scale, fy=resize_scale) cv2.imwrite("images/tmp/single_result.jpg", im0) # 目前的情况来看,应该只是ubuntu下会出问题,但是在windows下是完整的,所以继续 self.right_img.setPixmap(QPixmap("images/tmp/single_result.jpg")) # 视频检测,逻辑基本一致,有两个功能,分别是检测摄像头的功能和检测视频文件的功能,先做检测摄像头的功能。 ''' ### 界面关闭事件 ### ''' def closeEvent(self, event): reply = QMessageBox.question(self, 'quit', "Are you sure?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.close() event.accept() else: event.ignore() ''' ### 视频关闭事件 ### ''' def open_cam(self): self.webcam_detection_btn.setEnabled(False) self.mp4_detection_btn.setEnabled(False) self.vid_stop_btn.setEnabled(True) self.vid_source = '0' self.webcam = True th = threading.Thread(target=self.detect_vid) th.start() ''' ### 开启视频文件检测事件 ### ''' def open_mp4(self): fileName, fileType = QFileDialog.getOpenFileName(self, 'Choose file', '', '*.mp4 *.avi') if fileName: self.webcam_detection_btn.setEnabled(False) self.mp4_detection_btn.setEnabled(False) # self.vid_stop_btn.setEnabled(True) self.vid_source = fileName self.webcam = False th = threading.Thread(target=self.detect_vid) th.start() ''' ### 视频开启事件 ### ''' # 视频和摄像头的主函数是一样的,不过是传入的source不同罢了 def detect_vid(self): # pass model = self.model output_size = self.output_size # source = self.img2predict # file/dir/URL/glob, 0 for webcam imgsz = 640 # inference size (pixels) conf_thres = 0.25 # confidence threshold iou_thres = 0.45 # NMS IOU threshold max_det = 1000 # maximum detections per image # device = self.device # cuda device, i.e. 0 or 0,1,2,3 or cpu view_img = False # show results save_txt = False # save results to *.txt save_conf = False # save confidences in --save-txt labels save_crop = False # save cropped prediction boxes nosave = False # do not save images/videos classes = None # filter by class: --class 0, or --class 0 2 3 agnostic_nms = False # class-agnostic NMS augment = False # ugmented inference visualize = False # visualize features line_thickness = 3 # bounding box thickness (pixels) hide_labels = False # hide labels hide_conf = False # hide confidences half = False # use FP16 half-precision inference dnn = False # use OpenCV DNN for ONNX inference source = str(self.vid_source) webcam = self.webcam device = select_device(self.device) stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx imgsz = check_img_size(imgsz, s=stride) # check image size save_img = not nosave and not source.endswith('.txt') # save inference images # Dataloader if webcam: view_img = check_imshow() cudnn.benchmark = True # set True to speed up constant image size inference dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt and not jit) bs = len(dataset) # batch_size else: dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt and not jit) bs = 1 # batch_size vid_path, vid_writer = [None] * bs, [None] * bs # Run inference if pt and device.type != 'cpu': model(torch.zeros(1, 3, *imgsz).to(device).type_as(next(model.model.parameters()))) # warmup dt, seen = [0.0, 0.0, 0.0], 0 for path, im, im0s, vid_cap, s in dataset: t1 = time_sync() im = torch.from_numpy(im).to(device) im = im.half() if half else im.float() # uint8 to fp16/32 im /= 255 # 0 - 255 to 0.0 - 1.0 if len(im.shape) == 3: im = im[None] # expand for batch dim t2 = time_sync() dt[0] += t2 - t1 # Inference # visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False pred = model(im, augment=augment, visualize=visualize) t3 = time_sync() dt[1] += t3 - t2 # NMS pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det) dt[2] += time_sync() - t3 # Second-stage classifier (optional) # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s) # Process predictions for i, det in enumerate(pred): # per image seen += 1 if webcam: # batch_size >= 1 p, im0, frame = path[i], im0s[i].copy(), dataset.count s += f'{i}: ' else: p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0) p = Path(p) # to Path # save_path = str(save_dir / p.name) # im.jpg # txt_path = str(save_dir / 'labels' / p.stem) + ( # '' if dataset.mode == 'image' else f'_{frame}') # im.txt s += '%gx%g ' % im.shape[2:] # print string gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh imc = im0.copy() if save_crop else im0 # for save_crop annotator = Annotator(im0, line_width=line_thickness, example=str(names)) if len(det): # Rescale boxes from img_size to im0 size det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round() # Print results for c in det[:, -1].unique(): n = (det[:, -1] == c).sum() # detections per class s += f"{n} {names[int(c)]}{'s' * (n > 1)}, " # add to string # Write results for *xyxy, conf, cls in reversed(det): if save_txt: # Write to file xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view( -1).tolist() # normalized xywh line = (cls, *xywh, conf) if save_conf else (cls, *xywh) # label format # with open(txt_path + '.txt', 'a') as f: # f.write(('%g ' * len(line)).rstrip() % line + '\n') if save_img or save_crop or view_img: # Add bbox to image c = int(cls) # integer class label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}') annotator.box_label(xyxy, label, color=colors(c, True)) # if save_crop: # save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', # BGR=True) # Print time (inference-only) LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)') # Stream results # Save results (image with detections) im0 = annotator.result() frame = im0 resize_scale = output_size / frame.shape[0] frame_resized = cv2.resize(frame, (0, 0), fx=resize_scale, fy=resize_scale) cv2.imwrite("images/tmp/single_result_vid.jpg", frame_resized) self.vid_img.setPixmap(QPixmap("images/tmp/single_result_vid.jpg")) # self.vid_img # if view_img: # cv2.imshow(str(p), im0) # self.vid_img.setPixmap(QPixmap("images/tmp/single_result_vid.jpg")) # cv2.waitKey(1) # 1 millisecond if cv2.waitKey(25) & self.stopEvent.is_set() == True: self.stopEvent.clear() self.webcam_detection_btn.setEnabled(True) self.mp4_detection_btn.setEnabled(True) self.reset_vid() break # self.reset_vid() ''' ### 界面重置事件 ### ''' def reset_vid(self): self.webcam_detection_btn.setEnabled(True) self.mp4_detection_btn.setEnabled(True) self.vid_img.setPixmap(QPixmap("images/UI/up.jpeg")) self.vid_source = '0' self.webcam = True ''' ### 视频重置事件 ### ''' def close_vid(self): self.stopEvent.set() self.reset_vid() if __name__ == "__main__": app = QApplication(sys.argv) mainWindow = MainWindow() mainWindow.show() sys.exit(app.exec_()) ———————————————— 版权声明:本文为CSDN博主「肆十二」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ECHOSON/article/details/122404926
-
一,双层for循环代码:# 方法一 print('打印乘法表') for i in range(1,10): for j in range(1,i+1): print('%d*%d=%d'%(j,i,i*j),end='\t') print('') 解析:1,当有两层for循环时,当外层循环完后,内层开始新一轮循环。如当j循环到1时,i循环从一到9,循环完后,j在开始新一轮循环。由此就有了数去结果最左边的九行。 2,%d*%d=%d,是字符串的格式化(这里的格式化并不是全部清除,恢复出厂设置那样,而是规定了格式,让他输出的结果按照规定的格式) 3,end="/t"是换行的意思,即每循环一次,换一次行。 二,双层while循环 代码: #方法二 print('打印乘法表') i = 1 while i <= 9: j = 1 while (j <= i): print(f'{i}*{j}={i * j}', end='\t') j += 1 print('') i += 1解析:1,j+=1表示每次训环j的值就增加一2,f'{i}*{j}={i * j}'是字符串的格式化,f是转换为浮点数类型。三,综合法代码:#方法三 print("打印九九乘法表:") for i in range(1, 10): for j in range(1, i + 1): print(f'{i}*{j}={i * j}', end='\t') print()输出结果同上。解析:1,先是循环的是i,此时j为1,当i循环到9时,开启下一次循环,j的范围变为(1,3),但取不到3,并开始j的下一次循环为2,之后i在从1循环到9,在开启新的循环,以此类推。
-
在我的职业生涯中,我写过、用过和看到过很多随意的脚本。一些人需要半自动化完成任务,于是它们诞生了。一段时间后,它们变得越来越大。它们在一生中可能转手很多次。我常常希望这些脚本提供更多的 命令行工具式 的感觉。但是,从一次性脚本到合适的工具,真正提高质量水平有多难呢?事实证明这在 Python 中并不难。搭建骨架脚本在本文中,我将从一小段 Python 代码开始。我将把它应用到 scaffold 模块中,并使用 click 库扩展它以接受命令行参数。 #!/usr/bin/python from glob import glob from os.path import join, basename from shutil import move from datetime import datetime from os import link, unlink LATEST = 'latest.txt' ARCHIVE = '/Users/mark/archive' INCOMING = '/Users/mark/incoming' TPATTERN = '%Y-%m-%d' def transmogrify_filename(fname): bname = basename(fname) ts = datetime.now().strftime(TPATTERN) return '-'.join([ts, bname]) def set_current_latest(file): latest = join(ARCHIVE, LATEST) try: unlink(latest) except: pass link(file, latest) def rotate_file(source): target = join(ARCHIVE, transmogrify_filename(source)) move(source, target) set_current_latest(target) def rotoscope(): file_no = 0 folder = join(INCOMING, '*.txt') print(f'Looking in {INCOMING}') for file in glob(folder): rotate_file(file) print(f'Rotated: {file}') file_no = file_no + 1 print(f'Total files rotated: {file_no}') if __name__ == '__main__': print('This is rotoscope 0.4.1. Bleep, bloop.') rotoscope() 本文所有没有在这里插入显示的代码示例,你都可以在 cid:link_5 中找到特定版本的代码。该仓库中的每个提交都描述了本文操作过程中一些有意义的步骤。这个片段做了几件事:INCOMINGARCHIVEARCHIVE/latest.txt作为一个示例,它很简单,但它会让你理解这个过程。使用 Pyscaffold 创建应用程序首先,你需要安装 scaffold 、 click 和 tox Python 库 。$ python3 -m pip install scaffold click tox安装 scaffold 后,切换到示例的 rotoscope 项目所在的目录,然后执行以下命令: $ putup rotoscope -p rotoscope \ --force --no-skeleton -n rotoscope \ -d 'Move some files around.' -l GLWT \ -u http://codeberg.org/ofosos/rotoscope \ --save-config --pre-commit --markdown Pyscaffold 会重写我的 README.md ,所以从 Git 恢复它: $ git checkout README.mdPyscaffold 在文档中说明了如何设置一个完整的示例项目,我不会在这里介绍,你之后可以探索。除此之外,Pyscaffold 还可以在项目中为你提供持续集成(CI)模板:打包: 你的项目现在启用了 PyPi,所以你可以将其上传到一个仓库并从那里安装它。文档: 你的项目现在有了一个完整的文档文件夹层次结构,它基于 Sphinx,包括一个 readthedocs.org 构建器。测试: 你的项目现在可以与 tox 一起使用,测试文件夹包含运行基于 pytest 的测试所需的所有样板文件。依赖管理: 打包和测试基础结构都需要一种管理依赖关系的方法。 setup.cfg 文件解决了这个问题,它包含所有依赖项。预提交钩子: 包括 Python 源代码格式工具 black 和 Python 风格检查器 flake8。查看测试文件夹并在项目目录中运行 tox 命令,它会立即输出一个错误:打包基础设施无法找到相关库。现在创建一个 Git 标记(例如 v0.2 ),此工具会将其识别为可安装版本。在提交更改之前,浏览一下自动生成的 setup.cfg 并根据需要编辑它。对于此示例,你可以修改 LICENSE 和项目描述,将这些更改添加到 Git 的暂存区,我必须禁用预提交钩子,然后提交它们。否则,我会遇到错误,因为 Python 风格检查器 flake8 会抱怨糟糕的格式。$ PRE_COMMIT_ALLOW_NO_CONFIG=1 git commit如果这个脚本有一个入口点,用户可以从命令行调用,那就更好了。现在,你只能通过找 .py 文件并手动执行它来运行。幸运的是,Python 的打包基础设施有一个很好的“罐装”方式,可以轻松地进行配置更改。将以下内容添加到 setup.cfg 的 options.entry_points 部分:console_scripts = roto = rotoscope.rotoscope:rotoscope这个更改会创建一个名为 roto 的 shell 命令,你可以使用它来调用 rotoscope 脚本,使用 pip 安装 rotoscope 后,可以使用 roto 命令。就是这样,你可以从 Pyscaffold 免费获得所有打包、测试和文档设置。你还获得了一个预提交钩子来保证(大部分情况下)你按照设定规则提交。CLI 工具化现在,一些值会硬编码到脚本中,它们作为命令 参数 会更方便。例如,将 INCOMING 常量作为命令行参数会更好。首先,导入 click 库,使用 Click 提供的命令装饰器对 rotoscope() 方法进行装饰,并添加一个 Click 传递给 rotoscope 函数的参数。Click 提供了一组验证器,因此要向参数添加一个路径验证器。Click 还方便地使用函数的内嵌字符串作为命令行文档的一部分。所以你最终会得到以下方法签名: @click.command() @click.argument('incoming', type=click.Path(exists=True)) def rotoscope(incoming): """ Rotoscope 0.4 - Bleep, blooop. Simple sample that move files. """ 主函数会调用 rotoscope() ,它现在是一个 Click 命令,不需要传递任何参数。选项也可以使用 环境变量 自动填充。例如,将 ARCHIVE 常量改为一个选项:@click.option('archive', '--archive', default='/Users/mark/archive', envvar='ROTO_ARCHIVE', type=click.Path())使用相同的路径验证器。这一次,让 Click 填充环境变量,如果环境变量没有提供任何内容,则默认为旧常量的值。Click 可以做更多的事情,它有彩色的控制台输出、提示和子命令,可以让你构建复杂的 CLI 工具。浏览 Click 文档会发现它的更多功能。现在添加一些测试。测试Click 对使用 CLI 运行器 运行端到端测试 提供了一些建议。你可以用它来实现一个完整的测试(在 示例项目 中,测试在 tests 文件夹中。)测试位于测试类的一个方法中。大多数约定与我在其他 Python 项目中使用的非常接近,但有一些细节,因为 rotoscope 使用 click 。在 test 方法中,我创建了一个 CliRunner 。测试使用它在一个隔离的文件系统中运行此命令。然后测试在隔离的文件系统中创建 incoming 和 archive 目录和一个虚拟的 incoming/test.txt 文件,然后它调用 CliRunner,就像你调用命令行应用程序一样。运行完成后,测试会检查隔离的文件系统,并验证 incoming 为空,并且 archive 包含两个文件(最新链接和存档文件)。 from os import listdir, mkdir from click.testing import CliRunner from rotoscope.rotoscope import rotoscope class TestRotoscope: def test_roto_good(self, tmp_path): runner = CliRunner() with runner.isolated_filesystem(temp_dir=tmp_path) as td: mkdir("incoming") mkdir("archive") with open("incoming/test.txt", "w") as f: f.write("hello") result = runner.invoke(rotoscope, ["incoming", "--archive", "archive"]) assert result.exit_code == 0 print(td) incoming_f = listdir("incoming") archive_f = listdir("archive") assert len(incoming_f) == 0 assert len(archive_f) == 2 要在控制台上执行这些测试,在项目的根目录中运行 tox 。在执行测试期间,我在代码中发现了一个错误。当我进行 Click 转换时, rotoscope 只是取消了最新文件的链接,无论它是否存在。测试从一个新的文件系统(不是我的主文件夹)开始,很快就失败了。我可以通过在一个很好的隔离和自动化测试环境中运行来防止这种错误。这将避免很多“它在我的机器上正常工作”的问题。搭建骨架脚本和模块我们可以使用 scaffold 和 click 完成一些高级操作。有很多方法可以升级一个普通的 Python 脚本,甚至可以将你的简单实用程序变成成熟的 CLI 工具。
-
Tuple概述在Python中使用元组(Tuple)存储一组信息,其特征如下:1、使用()定义元组2、元组中使用逗号 , 分割各元素;各元素类型可不一致。3、元组的索引(下标)从0开始4、可使用len(元组)求元组的元素个数5、元组元素个数 = 元组索引最大值 + 16、通过元组[索引]的方式获取元组中的元素简单来说:Tuple在Python中表示一种“大小固定的有序序列”Tuple与英语之前,有位可爱的小伙伴问我:为什么Java里面有种集合叫Map,而不是叫其它名字?这个挺好解释和理解的。今天,他又追问我:Python语言中的Tuple到底是什么意思?怎么要取这么个名字呢?要回答这个问题,我们可能要从英语单词开始说起;我们先来瞅瞅英语中对于倍数的表示:倍数含义couple2倍triple3倍quadruple4倍quintuple5倍sextuple6倍……centuple100倍所以,在英语中-tuple后缀表示倍数的含义。Tuple与数学大约在1940年,数学中出现了有序数对的概念,它常表示为2-tuple。什么是有序数对呢?顺序的两个数a和b组成的数对,数学符号记作(a,b)叫做有序数对。所谓有序,是指一个2-tuple的元素顺序是固定的,例如(a,b)和(b,a)是不同的有序数对。有序数对可以准确的表示平面上的一点,也就是坐标(x,y)。3个有序数列怎么表示呢,可以写为(1,(2,3)),也可以直接写成(1,2,3)。 扩展到一般情况,n个有序数列,就被表示为n-tuple(n是正整数)。 把有序的元素写在( )内,再用逗号分隔;例如(9,5,2,7,6)就表示一个5-tuple。这就是Tuple在数学中的由来。Tuple与编程后来,编程语言从数学中引入了Tuple;中国的科技文献将其翻译成了元组。说实话,这个翻译有点让人捉摸不透。如果,仅仅从字面意思是很难理解这种数据结构的特点。所以,我们可以回归到数学:在数学定义中Tuple用来表示一个有限且有序的序列;它的长度不可变且元素有序。
-
python正则表达式括号python中re库函数的简单用法1re.findall(pattern,string)匹配所有符合正则表达式的字符,返回一个列表1re.search(pattern,string)查找第一个符合正则表达式的字符,返回一个Matcher对象。用group()或groups()方法取值1re.match(pattern,string)查找第一个符合正则表达式的字符,要求完全符合,返回一个Matcher对象。用group()或groups()方法取值正则表达式中的圆括号()的作用是对字符或元字符分组。我错把它的作用认为是将圆括号内的字符看成一个整体。尽管在一些正则测试网站上,进行匹配时,把括号内的字符看成一个整体来匹配也能匹配到想要的结果。测试网站如:regex101等然而在在写python程序的时候,会出现不是我想要的结果。如果正则表达式中多出使用了圆括号进行分组的话。在使用findall方法匹配结果就会只有分组的结果(即括号内表达式匹配的内容),而不是整个表达式所匹配的内容。如果使用search方法匹配,对返回的Matcher对象调用group()方法可以获取完整的结果。但是在需要匹配多个结果时,还得用findall所以在使用正则表达式时,若像我不太熟悉的话,避免使用圆括号来把一段表达式看成一个整体。python正则表达式入门教程括号及字符数据分析遇到字符串处理会有两个阶段涉及到正则表达式,一个是在数据库阶段一个是Python处理阶段。作为一个小白学习正则也遇到很多弯路和难理解的点,梳理梳理学习的过程。hive里面正则表达式可以用regexp_extract()在select里进行返回指定要求的内容,也可以用regexp在where里进行指定要求的限制条件;python里面re.findall()或者df.str.extract()(pandas功能);正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。学习正则需要记住两类知识点加上实际案例的联系就能很快的理解和掌握。正则中语法规范:括号区别正则表达式中存在(),[],{}1、():匹配小括号内的字符串,可以是一个,也可以是多个,常跟“|”(或)符号搭配使用,是多选结构的。() 是为了提取匹配的字符串。表达式中有几个()就有几个相应的匹配字符串例:string=‘我正在学习python3的正则表达式,现在的日期是2019-01-22’目的给定指定字符串进内容进行精准匹配获取pythonhiveselect regexp_extract(string,’(python)’,1) 返回结果为:python,1代码返回正则的第几个括号中的内容pythonre.findall(’(python)’,string)返回结果为:python2、【】:匹配字符组内的字符,比如咱们常用的[0-9a-zA-Z.*?!]等,在[]内的字符都是字符,不是元字符,比如“0-9”、“a-z”这中间的“-”就是连接符号,表示范围的元字符,如果写成[-!?*(]这样的话,就是普通字符例:string=‘我正在学习python3的正则表达式,现在的日期是2019-01-22’目的给定字符进内容匹配获取pythonhiveselect regexp_extract(string,’[a-z]’,0) 返回结果为:python,0代码返回符合正则的内容,如果有小括号可以写1(如'([a-z]+)')pythonre.findall(’[a-z]+’,string)返回结果为:python目的给定字符进内容匹配获取日期2019-01-22hiveselect regexp_extract(string,’([0-9]+.[0-9]+.[0-9]+)’,1) 返回结果为:2019-01-22pythonre.findall(’[0-9]+.[0-9]+.[0-9]+’,string)返回结果为:2019-01-22需求增加如果我要只需日期22这个部分pythonre.findall(’[0-9]+.[0-9]+.([0-9]+)’,string)返回结果为:22,和上面的对比发现在最后一个[0-9]+外面加了一个小括号,有小括号就返回小括号里面的内容3、{ }一般用来表示匹配的长度,比如 \s{3} 表示匹配三个空格,\s{1,3}表示匹配一到三个空格例:string=‘我正在学习python3的正则表达式,现在的日期是2019-01-22’目的取出日期数据部分结果为2019,01,22pythonre.findall(’([0-9]{2,4})’,string) 返回结果为:[2019,01,22],python3中到3是一个数字,所以指定数据个数为2-4的就为日期部分的数字常用正则表达式匹配名匹配表达式例子转义符\“n”匹配字符“n”。"\n"匹配一个换行符。串行"\\"匹配"\"而"\("则匹配"("开始位置^"abc,bac"匹配b开头的bac[^b]([a-z]{3})结束位置$"abce,abcd"匹配d结尾字母[a-z]+d$表达式0次或多次*表达式1次或多次+表达式0次或1次?除\n任意字符.单词边界\b“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”非单词边界\B“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”换页符\f空白行\n\s*\r首尾空白字符^\s*\s*$中文字符[\u4e00-\u9fa5]双字节字符(包含汉子在内)[^\x00-\xff]数字[0-9]或\d非数字\D小写字母[a-z]大写字母[A-Z]大小写字母[a-zA-Z]英文加数字a-z0-9
-
一、前言今天分享一个Python 制作透明背景的电子印章的代码,代码是通过网络获得并整理的,大家可以参考和学习。二、步骤解析代码我已调试过了,下面是操作步骤:将代码复制到你的py文件中,保存在本地C盘根目录下,名为:seal.py在运行代码时,根据提示安装相应模块根据你的实际情况修改代码中相应参数Win+R运行cmd,在命令行中输入:python C:/seal.py回车查看结果可以看到命令行中打印出相应信息,等待图片生成即可至此,我们就完成了Python 制作透明背景的电子印章的程序执行,大家喜欢的记得支持一下,有遇到问题的随时找我沟通。三、源代码''' Python制作透明背景的电子印章 ''' # 导入包 from PIL import Image,ImageFont,ImageDraw, ImageFilter from math import pi, cos, sin, tan from random import randint # 定义方法 def is_Chinese(ch): '''判断字符是否为中文''' if '\u4e00' <= ch <= '\u9fff': return True return False def pentagram(x, y, R, yDegree=0): ''' 计算五角星各个顶点 int R:五角星的长轴 int x, y:五角星的中心点 int yDegree:长轴与y轴的夹角 ''' rad = pi / 180 # 每度的弧度值 r = R * sin(18 * rad) / cos(36 * rad) # 五角星短轴的长度 # 求取外圈点坐标 RVertex = [(x - (R * cos((90 + k * 72 + yDegree) * rad)), y - (R * sin((90 + k * 72 + yDegree) * rad))) for k in range(5)] # 求取内圈点坐标 rVertex = [(x - (r * cos((90 + 36 + k * 72 + yDegree) * rad)), y - (r * sin((90 + 36 + k * 72 + yDegree) * rad))) for k in range(5)] # 顶点左边交叉合并 vertex = [x for y in zip(RVertex, rVertex) for x in y] return vertex def circle(x, y, r): '''计算圆的上下左右切点''' return (x - r, y - r, x + r, y + r) # 定义类 class Stamp: def __init__(self, edge = 5, # 图片边缘空白的距离 H = 160, # 圆心到中层文字下边缘的距离 R = 250, # 圆半径 border = 13, # 字到圆圈内侧的距离 r = 90, # 五星外接圆半径 fill = (255, 0, 0, 120),# 印章颜色, 默认纯红色, 透明度0-255,建议90-180 words_up = "", # 上部文字 angle_up = 270, # 上部文字弧形角度 font_size_up = 80, # 上部文字大小 font_xratio_up = 0.66, # 上部文字横向变形比例 stroke_width_up = 2, # 上部文字粗细,一般取值0,1,2,3 words_mid="", # 中部文字 angle_mid = 72, # 中部文字弧形角度 font_size_mid = 60, # 中部文字大小 font_xratio_mid = 0.7, # 中部文字横向变形比例 stroke_width_mid=1, # 中部文字粗细,一般取值0,1,2 words_down="",# 下部文字 angle_down = 60, # 下部文字弧形角度 font_size_down = 20, # 下部文字大小 font_xratio_down = 1, # 下部文字横向变形比例 stroke_width_down=1, # 下部文字粗细,一般取值0,1,2 img_wl_path = "", # 纹理图路径 save_path = "" # 保存图片路径 ): # 打开纹理图像,随机截取旋转 self.img_wl = Image.open(img_wl_path) # 图像初始设置为None self.img = None self.save_path = save_path self.fill = fill # 印章颜色 self.edge = edge # 图片边缘空白的距离 self.H = H # 圆心到中层文字下边缘的距离 self.R = R # 圆半径 self.r = r # 五星外接圆半径 self.border = border # 字到圆圈内侧的距离 self.words_up = words_up # 上部文字 self.angle_up = angle_up # 上部文字弧形角度 self.font_size_up = font_size_up # 上部文字大小 self.font_xratio_up = font_xratio_up # 上部文字横向变形比例 self.stroke_width_up = stroke_width_up # 上部文字粗细,一般取值0,1,2,3 self.words_mid = words_mid # 中部文字 self.angle_mid = angle_mid # 中部文字弧形角度 self.font_size_mid = font_size_mid # 中部文字大小 self.font_xratio_mid = font_xratio_mid # 中部文字横向变形比例 self.stroke_width_mid = stroke_width_mid # 中部文字粗细,一般取值0,1,2,3 self.words_down = words_down # 下部文字 self.angle_down = angle_down # 下部文字弧形角度 self.font_size_down = font_size_down # 下部文字大小 self.font_xratio_down = font_xratio_down # 下部文字横向变形比例 self.stroke_width_down = stroke_width_down # 中部文字粗细,一般取值0,1,2,3 def draw_rotated_text(self, image, angle, xy, r, word, fill, font_size, font_xratio, stroke_width, font_flip = False, *args, **kwargs): """ image:底层图片 angle:旋转角度 xy:旋转中心 r:旋转半径 text:绘制的文字 fill:文字颜色 font_size:字体大小 font_xratio:x方向缩放比例(印章字体宽度较标准宋体偏窄) stroke_width: 文字笔画粗细 font_flip:文字是否垂直翻转(印章下部文字与上部是相反的) """ # 加载字体文件-直接使用windows自带字体,中文用simsun, 英文用arial if is_Chinese(word): font = ImageFont.truetype("C:/Windows/Fonts/simsun.ttc", font_size, encoding="utf-8") else: font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", font_size, encoding="utf-8") # 获取底层图片的size width, height = image.size max_dim = max(width, height) # 创建透明背景的文字层,大小4倍的底层图片 mask_size = (max_dim * 2, max_dim * 2) # 印章通常使用较窄的字体,这里将绘制文字的图层x方向压缩到font_xratio的比例 mask_resize = (int(max_dim * 2 * font_xratio), max_dim * 2) mask = Image.new('L', mask_size, 0) # 在上面文字层的中心处写字,字的左上角与中心对其 draw = ImageDraw.Draw(mask) # 获取当前设置字体的宽高 bd = draw.textbbox((max_dim, max_dim), word, font=font, align="center", *args, **kwargs) font_width = bd[2] - bd[0] font_hight = bd[3] - bd[1] # 文字在圆圈上下的方向,需要通过文字所在文字图层的位置修正,保证所看到的文字不会上下颠倒 if font_flip: word_pos = (int(max_dim-font_width/2), max_dim+r-font_hight) else: word_pos = (int(max_dim-font_width/2), max_dim-r) # 写字, 以xy为中心,r为半径,文字上边中点为圆周点,绘制文字 draw.text(word_pos, word, 255, font=font, align="center", stroke_width = stroke_width, *args, **kwargs) # 调整角度,对于Π*n/2的角度,直接rotate即可,对于非Π*n/2的角度,需要先放大图片以减少旋转带来的锯齿 if angle % 90 == 0: rotated_mask = mask.resize(mask_resize).rotate(angle) else: bigger_mask = mask.resize((int(max_dim*8*font_xratio), max_dim*8), resample=Image.BICUBIC) rotated_mask = bigger_mask.rotate(angle).resize(mask_resize, resample=Image.LANCZOS) # 切割文字的图片 mask_xy = (max_dim*font_xratio - xy[0], max_dim - xy[1]) b_box = mask_xy + (mask_xy[0] + width, mask_xy[1] + height) mask = rotated_mask.crop(b_box) # 粘贴到目标图片上 color_image = Image.new('RGBA', image.size, fill) image.paste(color_image, mask) def draw_stamp(self): #创建一张底图,用来绘制文字 img = Image.new("RGBA",(2*(self.R+self.edge),2*(self.R+self.edge)),(255,255,255,0)) draw = ImageDraw.Draw(img) #绘制圆弧, R为外边缘,width往圆心算 draw.arc(circle(self.R+self.edge, self.R+self.edge, self.R), start=0, end=360, fill=self.fill, width = self.border) #绘制多边形 draw.polygon(pentagram(self.R+self.edge,self.R+self.edge,self.r), fill=self.fill, outline=self.fill) #绘制上圈文字 angle_word = self.angle_up / len(self.words_up) angle_word_curr = ((len(self.words_up)-1) / 2) * angle_word for word in self.words_up: self.draw_rotated_text(img, angle_word_curr, (self.R+self.edge,self.R+self.edge), self.R-self.border*2, word, self.fill, self.font_size_up, self.font_xratio_up, self.stroke_width_up) angle_word_curr = angle_word_curr - angle_word #绘制中层文字 angle_word = self.angle_mid / len(self.words_mid) angle_word_curr = -((len(self.words_mid)-1) / 2) * angle_word for word in self.words_mid: self.draw_rotated_text(img, 0, (self.R+self.edge+ self.H*tan(angle_word_curr*pi/180),self.R+self.edge), self.H, word, self.fill, self.font_size_mid, self.font_xratio_mid, self.stroke_width_mid, font_flip = True) angle_word_curr = angle_word_curr + angle_word #绘制下圈文字 angle_word = self.angle_down / len(self.words_down) angle_word_curr = -((len(self.words_down)-1) / 2) * angle_word for word in self.words_down: self.draw_rotated_text(img, angle_word_curr, (self.R+self.edge,self.R+self.edge), self.R-self.border*2, word, self.fill, self.font_size_down, self.font_xratio_down, self.stroke_width_down, font_flip = True) angle_word_curr = angle_word_curr + angle_word # 随机圈一部分纹理图 pos_random = (randint(0,200), randint(0,100)) box = (pos_random[0], pos_random[1], pos_random[0]+300, pos_random[1]+300) img_wl_random = self.img_wl.crop(box).rotate(randint(0,360)) # 重新设置im2的大小,并进行一次高斯模糊 img_wl_random = img_wl_random.resize(img.size).convert('L').filter(ImageFilter.GaussianBlur(1)) # 将纹理图的灰度映射到原图的透明度,由于纹理图片自带灰度,映射后会有透明效果,所以fill的透明度不能太低 L, H = img.size for h in range(H): for l in range(L): dot = (l, h) img.putpixel(dot, img.getpixel(dot)[:3]+(int(img_wl_random.getpixel(dot)/255*img.getpixel(dot)[3]),)) # 进行一次高斯模糊,提高真实度 self.img = img.filter(ImageFilter.GaussianBlur(0.6)) def show_stamp(self): if self.img: self.img.show() def save_stamp(self): if self.img: self.img.save(self.save_path) if __name__ == '__main__': # 上面的字 words_up = "小刘带你学py技术社区" # 中间的字 words_mid="社区专用章" # 下面的字 words_down="2022092415" # 背景图片路径 img_wl_path = "D:\Back1.jpg" # 印章保存路径 save_path = "D:\A\Project_1\stamp.png" # 执行方法 stamp = Stamp(words_up=words_up,words_mid=words_mid,words_down=words_down,img_wl_path=img_wl_path,save_path=save_path) stamp.draw_stamp() stamp.show_stamp() stamp.save_stamp()
-
1 sample(序列a,n)sample(序列a,n)功能:从序列a中随机抽取n个元素,并将n个元素生以list形式返回。例:1234from random import randint, sampledate = [randint(10,20) for _ in range(10)]c = sample(date, 5)print(c)1# 输出:[12, 17, 10, 12, 17]randint(10,20) for _ in range(10):从10~20间随机抽取10个数;2 random sample()sample()方法返回一个列表,其中从序列中随机选择指定数量的项目。注意:此方法不会更改原始顺序。实例返回一个包含列表中任何两项的列表:123import randommylist = ["apple", "banana", "cherry"]print(random.sample(mylist, k=2))语法random.sample(sequence, k)参数必需的描述sequence是一个序列。 可以是任何序列:列表,集合,范围等。k是返回列表的大小补充:Pandas-sample随机抽样实例按行抽取12345678import pandas as pd#创建DataFrame数据info = pd.DataFrame({'name': ['李四', '王五', '小贝', '虞姬'], 'age': [18, 19, 20, 18], 'sex': ['男', '男', '女','女' ], 'class': ['5班', '4班', '5班','3班' ]})#默认随机选择两行print(info.sample(n=2))按列抽取12345678import pandas as pd#创建DataFrame数据info = pd.DataFrame({'name': ['李四', '王五', '小贝', '虞姬'], 'age': [18, 19, 20, 18], 'sex': ['男', '男', '女','女' ], 'class': ['5班', '4班', '5班','3班' ]})#随机选择两列print(info.sample(n=2,axis=1))
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签