当前位置: 首页 > news >正文

WebUI自动化学习(Selenium+Python+Pytest框架)003

1.元素操作

在成功定位到元素之后,我们需要对元素进行一些操作动作。常用的元素操作动作有:

(1)send_keys()

               键盘动作:向浏览器发送一个内容,通常用于输入框输入内容或向浏览器发送快捷键

(2)click()

                鼠标左键单击,通常用于点击按钮

(3)clear()

                清空内容,通常用于输入框内容清空

                注意:在进行测试实战时,向输入框发送内容前,要养成先清空的习惯。如果输入前输入框有内容,则send_keys()会在原内容上追加输入,从而影响测试结果。

代码示例

# 导包
from time import sleepfrom selenium import webdriver# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开浏览器
driver.get('https://www.baidu.com')
# 展示效果
sleep(1)
# 实现需求
element_find = driver.find_element_by_id('kw')
element_Button = driver.find_element_by_id('su')
# 输入文本
element_find.send_keys('元素')
sleep(1)
# 清空
element_find.clear()
sleep(1)
# 再次输入,实际操作中,养成习惯,先清空再输入,防止输入框原本有内容影响脚本执行
element_find.send_keys('定位')
sleep(1)
# 点击搜索
element_Button.click()sleep(3)# 关闭浏览器
driver.quit()

2.浏览器操作

除了对元素进行操作外,对浏览器窗口的操作也是必不可少的,常见的浏览器操作如下:

(1)get()

        在浏览器窗口打开指定的网页        driver.get(URL)

(2)maximize_window()

        将浏览器窗口最大化        driver.maximize_window()

(3)set_window_size()

        设置浏览器窗口尺寸(单位是像素)        driver.set_window_size(窗口宽,窗口高)

(4)set_window_positions()

        设置浏览器窗口打开位置(单位是像素,设置的坐标为窗口左上角的坐标)

        driver.set_window_positions(x,y)

(5)back()

        页面回退,等于网页地址栏左上角的返回箭头

(6)forward()

        页面前进,等于网页地址栏左上角的→箭头

(7)refresh()

        刷新页面,等于按住F5快捷键刷新或者点击按钮

(8)close()

        关闭当前网页,等于点击一个网页标签上的X

(9)quit()

        关闭浏览器,等于在浏览器右上角点X,关闭当前浏览器的所有页面。

代码示例

# 导包
from time import sleepfrom selenium import webdriver# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开浏览器
driver.get('https://www.baidu.com')
# 展示效果
sleep(1)
# 最大化浏览器窗口
driver.maximize_window()
sleep(1)
# 设置浏览器窗口为指定大小,单位是像素点
# 浏览器会保证一个最小窗口,能显示URL和基本按钮,不会任意缩小到无限小
driver.set_window_size(800,1000)
sleep(1)
# 设置浏览器打开位置
# 以屏幕左上角为(0,0)
driver.set_window_position(0,0)
sleep(1)
# 任意搜索一个内容(测试准备)
driver.find_element_by_id('kw').send_keys('test')
driver.find_element_by_id('su').click()
sleep(2)
# 浏览器后退按钮(返回上一页),返回百度首页
driver.back()
sleep(1)
# 浏览器前进按钮(前进回到返回前那一页),返回搜索页
driver.forward()
sleep(1)
# 刷新页面
# 向服务器重新发起请求
driver.refresh()
sleep(2)
# 打开百度热搜页面
driver.maximize_window()
driver.find_element_by_class_name('toindex').click()
driver.find_element_by_xpath('//*[@id="s-hotsearch-wrapper"]/div/a[1]/div').click()
sleep(2)
# 获取当前页title和current_url两个属性(get的这个页面,不是新打开页页面)
# 虽然新打开了百度热搜页面,也在最上层打开了,但是这是浏览器的操作,代码的操作对象还是百度首页
print(driver.title)
print(driver.current_url)
# 关闭单个页面(,没有进行页面切换动作,关闭的是跳转前的页面,不是新打开额页面)
driver.close()
sleep(2)
# 关闭浏览器
driver.quit()

3.获取元素信息

在执行测试任务时,如果只是操作浏览器进行指定动作而不判断交互结果是否符合预期,那么测试就是无效的。获取元素的相关信息并使用断言进行判断,能够帮助我们判断元素是否在进行了指定操作后做出了响应的交互变化,例如勾选、页面切换、URL变化等。获取元素信息主要有以下方法:

(1)text

        获取元素的文本信息,通常用于弹窗警告信息的提取

        element.text

(2)size

        获取元素的尺寸大小,通常用于页面布局判断

        element.size

(3)is_displayed()

        判断元素是否在页面肉眼可见(是否显示在页面上),通常用于权限验证

        element.is_displayed()

(4)is_enabled()

        判断元素是否可用,通常用于权限控制(不登录,某些功能能看到但是不能用)

        element.is_enabled()

(5)get_attribute()

        获取元素的某个属性值,通常用于业务操作之间的依赖参数传递

        element.get_attribute(属性名)

(6)is_selected()

        判断元素是否被选中,通常用于选择框或选择按钮

         element.is_selected()

代码示例

# 导包
from time import sleepfrom selenium import webdriver# 实例化浏览器对象
driver = webdriver.Chrome()# 打开浏览器
driver.get('https://www.baidu.com')# 展示效果sleep(2)# 实现需求
# 1.size 返回元素大小
# 应用场景:判断页面布局是都符合预期
find_element = driver.find_element_by_id('kw')
print('搜索框的大小是:', find_element.size)# 2.text获取元素的文本
# 应用场景:切换页面后对特定元素的文本信息进行获取,通常用于断言
find_button = driver.find_element_by_class_name('hot-refresh-text')
print('换一换按钮的文本内容是:', find_button.text)# 3.get_attribute()获取属性值
# 应用场景:获取指定属性值,当做参数传递给其他方法使用
element1 = driver.find_element_by_xpath('//*[text()="关于百度"]')
driver.get(element1.get_attribute('href'))
sleep(2)# 4.is_displayed() 判断元素是否肉眼可见(是否在页面显示),可见返回True,不可见返回False
# 应用场景:判断元素是否显示
# 元素隐藏显示,不影响元素定位,不意味着元素一定不存在
driver.get('https://www.baidu.com')
sleep(1)
hotsearch_element = driver.find_element_by_id('hotsearch_data')
print(hotsearch_element.is_enabled())# 5.is_enabled()判断元素是否可用
# 应用场景:判断元素是否能够进行交互,不符合要求的时候某些功能不能使用时# 6.is_selected()判断元素是否选中
# 应用场景:判断单选或复选框是否被选中,例如购物车# 关闭浏览器
driver.quit()

4.鼠标动作

Selenium将鼠标动作全部封装在了ActionChains()类中,在进行鼠标动作时需要以下步骤:

①实例化鼠标对象:action = ActionChains(driver)

②调用鼠标动作方法:action.click()

        包括方法如下:

        单击        click(element)

        双击        double_click(element)

        右键单击        context_click(element)

        在元素上方悬停        move_to_element(element)

        拖拽        dreg_and_drop(初始element,目标element)

③调用.perform()方法执行步骤②的动作

代码示例

# 导包
from time import sleepfrom selenium import webdriver
from selenium.webdriver import ActionChains# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开浏览器
driver.get('https://www.baidu.com')
# 浏览器窗口最大化
driver.maximize_window()
# 隐式等待
driver.implicitly_wait(10)
sleep(2)
# 实例化鼠标对象
action1 = ActionChains(driver)
#
# 单击百度首页新闻按钮
news_element = driver.find_element_by_link_text('新闻')
action1.click(news_element).perform()  # 调用动作函数并执行,即点击百度首页新闻超链接
# 以上代码可以简写为
# action.click(driver.find_element_by_link_text('新闻')).perform()
sleep(5)
# 测试准备:关闭新打开的新闻页,当前阶段忽略此段代码
driver.switch_to.window(driver.window_handles[-1])
print(driver.title)
driver.close()
driver.switch_to.window(driver.window_handles[0])
sleep(2)
print(driver.title)# 在百度输入框输入“test”并双击选中输入的文本
search_element = driver.find_element_by_css_selector('#kw')
search_element.send_keys('test')
driver.find_element_by_id('su').click()
sleep(3)"""
这里留个疑问,欢迎各位小伙伴解惑:
在下面代码大家可以看到,我新实例化了一个鼠标对象action2。
因为之前实例化的那个鼠标对象action1在切换新闻页面后再次使用就报错了
错误提示‘百度输入框’这个元素在https://news.baidu.com找不到,但是我driver已经切回首页了呀???
代码里也打印了切换页面之后的title,页面是切换成功了的
也就是说,虽然driver层完成了页面切换,action1在切换页面后的操作对象还留在新闻页没有切回来
疑问:为什么没有随driver切换呢?要怎样才能完成切换操作呢?还是说必须得新实例化一个鼠标???
"""
action2 = ActionChains(driver)
action2.double_click(search_element).perform()
sleep(2)# 在百度输入框右键
action2.context_click(search_element).perform()
sleep(2)# 在百度首页,设置上方悬停
action2.move_to_element(driver.find_element_by_css_selector('#u > a.pf')).perform()
sleep(2)
# 将百度热搜拖拽到搜索框,百度热搜地址出现在输入框
search_element.clear()
hot_search = driver.find_element_by_link_text('百度首页')
action2.drag_and_drop(hot_search, search_element).perform()
sleep(2)
# 关闭浏览器
driver.quit()

5.键盘动作

Selenium的键盘动作都使用send_key()函数来实现,如果需要联合使用多个键,可以调用Keys类来实现。

用法如下:

例如Ctrl+C:        element.send_keys(Keys.CONTRAL,'c')

其他快捷键用法类似,还好包含了以下常用键:

删除:BACK_SPACE(即键盘上最常用的删除键,一次删除一个字符或汉字,在某些品牌电脑上这个键写的是Delete,某些品牌写的是Backspace)

空格:SPACE

回车:ENTER

制表符:TAB(即键盘上的Tab键)

其他内容可以自行进入底层代码查看(将光标放在Keys上,Ctrl+B可以进入它的底层封装代码,都封装了哪些键盘,有具体说明)        

代码示例

# 导包
from time import sleepfrom selenium import webdriver
from selenium.webdriver.common.keys import Keys# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开浏览器
driver.get('https://www.baidu.com')
# 浏览器窗口最大化
driver.maximize_window()
# 展示效果
sleep(1)
text_element = driver.find_element_by_id('kw')
text_element.send_keys('Test')
sleep(1)
# 删除一个字符
text_element.send_keys(Keys.BACKSPACE)
sleep(1)
# 空格+tab,同时按
text_element.send_keys(Keys.SPACE, Keys.TAB)
sleep(1)
# 回车
text_element.send_keys(Keys.ENTER)
sleep(1)
# 全选
text_element.send_keys(Keys.CONTROL, 'a')
sleep(1)
text_element.send_keys(Keys.CONTROL, 'c')
text_element.send_keys(Keys.CONTROL, 'v')
text_element.send_keys(Keys.ENTER)
sleep(1)
# 关闭浏览器
driver.quit()

6.元素等待

为什么要设置元素等待:由于我们在测试过程当中受网络、测试机性能、加载速度等环境影响,元素并不是永远都能够在打开页面的一瞬间全部加载完成的(还有些页面是动态加载的,例如淘宝),这就会导致代码执行到了,但是元素没有加载完成,代码报错。

为代码添加一个等待机制,等待元素加载完成再进行查找和操作,会大大减少因环境影响而导致的报错,提升工作效率。

(1)隐式等待

        ①等待机制

                在定位元素时,如果找到了元素,则不触发等待

                没有找到,则间隔一段时间后再去定位,直到找到元素或达到设定的最长等待时间为止

                找不到则抛出异常:NoSuchElementException

        ②优缺点

                优点:全局只需要设置1次,只要有元素找不到就会触发一次。

                缺点:

                          间隔时间不受控制,只能设置最大等待时长

                          作用于全局,只要有一个找不到则全局等待

                          遇到动态加载页面会引起执行效率过低。例如:如果遇到动态加载的页面,页面中刚好有元素未加载完成,触发了等待,最长等待时长为10s。但是这个元素很快就加载完成了,只用了2s。但是此时动态加载的元素还需要等待用户操作或者等够动态变换的时间才加载,这时隐式等待是不会关闭的,会等够10s或者等到动态元素加载完成才关闭。大大的浪费了时间。

(2)显式等待        

        ①等待机制

                在定位元素时,如果找到了元素,则不触发等待

                没有找到,则间隔一段时间后再去定位,直到找到元素或达到设定的最长等待时间为止

                找不到则抛出异常:TimeoutException

        ②优缺点

                优点:

                        等待间隔受控,可以自定义设置。

                        只作用于一个元素

                缺点:

                        每个需要等待的元素都要设置一次

代码示例

# 导包
from time import sleepfrom selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.support.wait import WebDriverWait# 实例化浏览器对象
driver = webdriver.Chrome()
# 打开浏览器
driver.get('https://www.baidu.com')
# 浏览器窗口最大化
driver.maximize_window()
# 隐式等待:通常设置10s
driver.implicitly_wait(10)
sleep(2)# 显示等待
"""
解析:
实例化等待对象WebDriverWait(),参数分别是浏览器驱动对象,等待最大时长,等待时间间隔
调用这个WebDriverWait()类的until()方法,参数是要定位的元素
返回值是元素对象,使用element1接收保存,供后续调用
意思是定义一个显式等待,最大等待时长10s,等待间隔为1s,用于查找id为'kw'的元素。
如果元素找到则返回元素对象,没有找到则每隔1s查找一次,直到找到元素或到达指定最大时长10s
注意:在实际测试工作中,最大时长通常设置为10s,实际已上线项目,通常最大等待时长为30s,再大就会影响用户体验了查找的时间间隔,默认是0.5s,缺省即默认0.5s,也可以自定义
"""
element1 = WebDriverWait(driver,10,1).until(lambda x: x.find_element_by_id('kw'))
# 关闭浏览器
driver.quit()

为什么until的参数要是一个匿名函数呢?我们可以看一下这个方法的底层,它要求参数需要是一个method即方法,那么我们使用匿名函数来充当参数就可以了。使用匿名函数变量X,来充当driver,写一个查找语句。如果不了解匿名函数的,可以去参考我之前的python学习笔记,函数那一篇。

                

相关文章:

WebUI自动化学习(Selenium+Python+Pytest框架)003

1.元素操作 在成功定位到元素之后,我们需要对元素进行一些操作动作。常用的元素操作动作有: (1)send_keys() 键盘动作:向浏览器发送一个内容,通常用于输入框输入内容或向浏览器发送快捷键 (2…...

python+Appium自动化:python多线程多并发启动appium服务

Python启动Appium 服务 使用Dos命令或者bat批处理来手动启动appium服务,启动效率低下。如何将启动Appium服务也实现自动化呢? 这里需要使用subprocess模块,该模块可以创建新的进程,并且连接到进程的输入、输出、错误等管道信息&…...

【计算机网络笔记】802.11无线局域网

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…...

用C++和python混合编写数据采集程序?

之前看过一篇文章,主要阐述的就是多种语言混合编写爬虫程序,结合各种语言自身优势写一个爬虫代码是否行得通?觉得挺有意思的,带着这样的问题,我尝试着利用我毕生所学写了一段C和python混合爬虫程序,目前运行…...

Android HCI日志分析案例1

案例1--蓝牙扫描设备过程分析 应用层发起搜索蓝牙设备,Android 官方提供的蓝牙扫描方式有三种,分别如下: BluetoothAdapter.startDiscovery(); //可以扫描经典蓝牙和BLE两种。BluetoothAdapter.startLeScan();//扫描低功耗蓝牙,…...

LangChain(0.0.339)官方文档四:Prompts下——prompt templates的存储、加载、组合和部分格式化

文章目录 一、 部分提示模板1.1 使用字符串值进行部分格式化(Partial with strings)1.2 使用函数进行部分格式化(Partial with functions) 二、Prompt pipelining2.1 String prompt pipelining2.2 Chat prompt pipelining 三、使用…...

鸿蒙开发笔记

最近比较火,本身也是做前端的,就抽空学习了下。对前端很友好 原视频地址:黑马b站鸿蒙OS视频 下载安装跟着视频或者文档就可以了。如果你电脑上安装的有node,但是开发工具显示你没安装,不用动咱们的node,直…...

「计算机网络」Cisco Packet Tracker计算机网络仿真器的使用

介绍 Cisco Packet Tracker:网络仿真工具,用于模拟网络配置。 (一) 配置交换机(Switch)(通过 带外管理) 带外:Out-of-Band, OOB写在前面:如何打开Console页…...

【已解决】if lock.acquire(block, timeout):KeyboardInterrupt

问题描述 Traceback (most recent call last): File "/media/visionx/monica/project/ResShift/app.py", line 134, in <module> demo.launch(shareFalse) File "/home/visionx/anaconda3/envs/ResShift/lib/python3.9/site-packages/gradio/bloc…...

将Excel中的数据导入shell脚本,并调用expect脚本

主脚本test.sh #!/bin/bash # 设置超时时间 set timeout 240 # 将 Excel 文件转换为 CSV 格式 # test.xlsx > temp.csv # 初始化一个二维数组 declare -A data # 逐行读取 CSV 文件&#xff0c;并将每个单元格的数据存储在二维数组中 row1 while IFS, read -r col1 col2 co…...

elementui el-table用span-method方法对相同的列名或行名进行合并

看到的一篇文章 同理 如果对第二列进行合并的话copy一下第一个方法&#xff0c;让值赋给第二个数组就可以 // 合并方法mergeCells({ row, column , rowIndex, columnIndex }) {debugger;if (columnIndex 1) {const _row this.spanArr[rowIndex];const _col _row > 0 ? …...

汇编语言实现音乐播放器

目标程序 用汇编语言实现一个音乐播放器&#xff0c;并支持点歌 Overview 乐曲是按照一定的高低、长短和强弱关系组成的音调&#xff0c;在一首乐曲中&#xff0c;每个音符的音高和音长与频率和节拍有关&#xff0c;因此我们要分别为3首要演奏的乐曲定义一个频率表和一个节拍…...

大型网站系统架构演化(Web)

大型网站系统架构演化 大型网站系统架构演化需要关注的维度涉及的技术演进过程单体架构垂直架构使用缓存改善网站性能缓存与数据库的数据一致性问题缓存技术对比Redis分布式存储方案Redis集群切片的常见方式Redis数据类型Redis 淘汰算法使用服务集群改善网站并发能力 大型网站系…...

三轴加速度计LIS2DW12开发(2)----基于中断信号获取加速度数据

三轴加速度计LIS2DW12开发.2--轮基于中断信号获取加速度数据 概述视频教学样品申请生成STM32CUBEMX串口配置IIC配置CS和SA0设置INT1设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置开启INT1中断设置传感器的量程配置过滤器链配置电源模式设置输出数据速率中断判断加速…...

Shell循环:whileuntil

一、特点&#xff1a;循环次数[一定]是固定的 二、while语句结构 while 条件测试 do 循环体 done 当条件测试成立&#xff08;条件测试为真&#xff09;&#xff0c;执行循环体 演示&#xff1a; 需求&#xff1a;每秒显示一个数字&#xff0c;一…...

Redis 安装部署

文章目录 1、前言2、安装部署2.1、单机模式2.1.1、通过 yum 安装&#xff08;不推荐&#xff0c;版本老旧&#xff09;2.1.1、通过源码编译安装&#xff08;推荐&#xff09; 2.2、主从模式2.3、哨兵模式2.4、集群模式2.5、其他命令2.6、其他操作系统 3、使用3.1、Java 代码 —…...

项目中遇到的半导体公司

作为一个技术人&#xff0c;我并不是亲美&#xff0c;从技术的实事求是角度讲&#xff0c;不得不感叹欧美的半导体技术。他们的datasheet能学到的东西太多太多&#xff1b;我甚至佩服他们缜密的逻辑。从他们的文章中领悟我们技术到底有多low&#xff0c;没办法一个一个了解所有…...

汇编:call与ret/retf指令

一、call指令 ​​​​​​​ 1.1 依据位移进行转移&#xff1a;call 标号 1.2 实现段间转移&#xff1a;call far ptr 标号 1.3 转移地址在寄存器中&#xff1a;call 16位寄存器 1.4 转移地址在内存中 1.4.1 call word ptr 内存单元地址 1.4.2 call dword ptr 内存单元地址…...

Fiddler抓包工具之高级工具栏中的重定向AutoResponder的用法

重定向AutoResponder的用法 关于Fiddler的AutoResponder重定向功能&#xff0c;主要是时进行会话的拦截&#xff0c;然后替换原始资源的功能。 它与手动修该reponse是一样的&#xff0c;只是更加方便了&#xff0c;可以创建相应的rules&#xff0c;适合批处理的重定向功能。 …...

如何基于OpenCV和Sklearn库开展数据降维

大家在做数据分析或者机器学习应用过程中&#xff0c;不可避免的需要对数据进行降维操作&#xff0c;好多垂直行业业务中经常出现数据量少但维度巨大的情况。数据降维的目的是为了剔除不相关或冗余特征&#xff0c;使得数据易用&#xff0c;去除无用数据&#xff0c;实现数据可…...

详解SpringAop开发过程中的坑

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…...

【海思SS528 | VDEC】MPP媒体处理软件V5.0 | VDEC的使用总结

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…...

Kubernetes sample-controller 例子介绍

sample-controller sample-controller 是 K8s 官方自定义 CDR 及控制器是实现的例子 通过使用这个自定义 CDR 控制器及阅读它的代码&#xff0c;基本可以了解如何制作一个 CDR 控制器 CDR 运作原理 网上有更好的文章&#xff0c;说明其运作原理&#xff1a; https://www.z…...

【C/C++指针】指针*与引用的区别

指针变量的值是所指对象的地址&#xff08;准确说是首地址&#xff0c;其类型定义其所指对象的字节长度&#xff09;引用变量的值是所引用对象本身的值 1 初始化 指针变量 可不初始化 且 可以更换指向对象 int *p;//此时是个野指针&#xff0c;该指针变量的值是任意值&#x…...

【ArcGIS Pro微课1000例】0039:制作全球任意经纬网的两种方式

本文讲解在ArcGIS Pro中制作全球任意经纬网的两种方式。 文章目录 一、生成全球经纬网矢量1. 新建地图加载数据2. 创建经纬网矢量数据二、布局生成经纬网1. 新建布局2. 创建地图框2. 创建经纬网一、生成全球经纬网矢量 以1:100万比例尺地图分幅为例,创建经差6、维差4的经纬网…...

【二叉树】练习题终章

二叉树的销毁 void BTreeDestroy(BTNode* root) {if (root NULL)return;BTreeDestroy(root->left);BTreeDestroy(root->right);free(root); }递归展示图 使用后序销毁&#xff0c;如果用前序销毁的话&#xff0c;就会找不到根对应的子树的地址.下面就不能被销毁了&…...

flutter开发实战-实现获取视频的缩略图封面video_thumbnail

flutter开发实战-实现获取视频的缩略图封面video_thumbnail 在很多时候&#xff0c;我们查看视频的时候&#xff0c;视频没有播放时候&#xff0c;会显示一张封面&#xff0c;可能封面没有配置图片&#xff0c;这时候就需要通过获取视频的缩略图来显示封面了。这里使用了video…...

Prompt Toolkit探索:打造交互式CLI应用

简介&#xff1a;prompt_toolkit 是一个 Python 的库&#xff0c;它提供了一系列功能丰富的用户界面元素&#xff0c;比如自动完成、语法高亮、多行编辑、提示等等&#xff0c;让你可以轻松地构建出功能强大的命令行工具。而且&#xff0c;这个库还被 IPython 和 pgcli 这样的知…...

【已解决】AttributeError: module ‘gradio‘ has no attribute ‘outputs‘

问题描述 AttributeError: module gradio has no attribute outputs 不知道作者用的是哪个gradio版本&#xff0c;最新的版本报错AttributeError: module gradio has no attribute outputs &#xff0c; 换一个老一点的版本会报错AttributeError: module gradio has no attribu…...

WPF Mvvm模式下面如何将事件映射到ViewModel层

前言 平常用惯了Command绑定,都快忘记传统的基于事件编程模式了,但是Commond模式里面有个明显的问题,就是你无法获取到事件源的参数。很多大聪明肯定会说,这还不简单,通过自己写控件,给控件加个自定义属性不就行了,想要啥事件就写啥事件进去,完全自主可控。但是对于写…...