快乐学习
前程无忧、中华英才非你莫属!

Python3.11下载安装与创建独立虚拟环境

zhangtongle阅读(2305)

一、python 下载安装

1.去https://www.python.org 官网,按照图示点击下载Python3.11.4

2. 双击下载好的安装包,按照图示选自定义安装路径,便于项目管理,并勾选添加环境变量复选框

备注:然后一路next就可以了,

3、快捷键win(窗口键)+ R 打开运行,并键入cmd

备注:ctrl+z 并回车就可以退出解释器。

4. 设置仓库地址
pip config set global.index-url https://pypi.douban.com/simple/

备注: 设置软件模块的仓库地址,让python的模块,从国内豆瓣源镜像仓库下载。这样就不会出现timeout超时异常,模块下载不下来等异常。

二、python 设置虚拟环境

1. 安装虚拟环境管理模块

pip install virtualenv
pip install virtualenvwrapper-win

2. 设置虚拟环境的系统环境变量

WORKON_HOME :D:\PyJob\virtualenv

D:\PyJob\virtualenv 这个路径要提前创建好,在PyJob文件夹下创建virtualenv 文件夹,用来存储各种独立的虚拟环境。防止冲突。

在Windows 10中,可以通过以下步骤快速打开系统环境变量:

1. 使用键盘快捷键 Win + X
2. 在弹出的菜单中,选择“系统”。
3. 在系统菜单中,点击“高级系统设置”。
4. 在弹出的对话框中,点击“环境变量”按钮。
5. 这将打开“环境变量”对话框,其中包含系统环境变量和用户环境变量的设置。

通过以上步骤,您可以快速打开系统环境变量并进行相应的设置。

3. 虚拟环境创建和管理

 mkvirtualenv -p D:\PyJob\py311\python.exe chatgpt  # 创建名字叫chatgpt的独立虚拟环境
 workon # 查看所有虚拟环境
 workon chatgpt # 进入和切换到chatgpt环境


备注:这样做的好处是,后期多个项目时,项目与项目之间不冲突,项目依赖的资源相互独立。

指定解释器,则使用
mkvirtualenv --python=python3安装路径 ztloo

包含系统解释器中已经安装的python包
mkvirtualenv test1 --system-site-packages(默认不包含系统环境中的python包)

删除独立虚拟环境
rmvirtualenv test1

如何与ChatGPT交流?ChatCatsy AI工具让你的对话更加智能!

zhangtongle阅读(1965)

📌 免责声明:本软件仅供学习测试使用,请勿使用本软件从事违法活动,否则一经发现,后果自负,将配合相关部门严厉打击。

本AI工具软件是基于ChatGPT技术研发而成,旨在提供更便捷、更智能的聊天体验。但请注意,该软件仅作为一种辅助工具,不能代替人类的判断和决策,也不能保证100%准确性和完整性。因此,使用本聊天软件所产生的任何结果和后果,本人不承担任何法律责任。用户需自行承担使用该软件的全部风险和责任,并且应该在使用前仔细阅读软件说明和功能介绍,了解其局限性和适用范围。最后,我们保留对免责声明的解释权和修改权,并且不对因软件使用导致的任何损失或损害承担法律责任。

第一章:软件介绍

🧑🏼‍🎨
ChatCatsy是一款完全由Python开发的桌面端软件,它可以与ChatGPT进行流畅的交流,并且具有类似Siri的语音交互功能。
只需说出“你好”,就能唤醒它。此外,ChatCatsy还包含了文字转换语音、生成字幕、音频功能以及音频转文字等多种实用功能。

为了满足用户的不同需求,ChatCatsy还提供了详细的设置功能,用户可以控制ChatGPT的版本模型、回答长度、随机性以及问答模式,包括官方API直连、记忆直连和记忆代理等多种模式。
此外,用户还可以对软件的外观进行设置,包括背景图、主题色和软件透明度等。

总之,ChatCatsy是一款功能强大、操作简便、界面美观的AI工具,可以帮助用户更加高效地进行文字和语音交流。如果你需要更多信息或者有任何疑问,请随时联系我们。我们非常期待与您合作,让ChatCatsy成为您的得力助手。

📌 说明:目前软件只支持Windows 版本,因为开发小哥手里暂时没有Mac电脑。当有些开发经费后,很快就能支持Mac 版本,敬请期待。


第二章:软件基本使用

🔑 step1: 获取官方网盘下载链接:

链接:https://pan.baidu.com/s/1Kk94l_X_weoQNli22S_MZg?pwd=abcd
提取码:abcd


🔑 step2: 把软件下载后,放在不含中文的文件夹里面。此软件是免安装的,双击即可使用。

🤖 软件版本区别:

ChatCatsyV1.0 : 内部不包含代理模式,需要自行连通国际互联网,并设为全局模式,才能使用内部功能。

ChatCatsyV1.1:内包含代理模式,不用连通国际互联网,便能使用软件内部问答模式,文字转语音。

注意:ChatCatsyV1.1 在V1.0的基础上,多了代理模式,如果在V1.1 使用内置代理模式,会导致语音转文字功能异常,因代理服务器暂时未支持语音转文字接口。如果想使用音频转文字功能,请联通国际互联网。


🔑 step3: 软件正版激活 打开软件后,如果是第一次使用,会弹窗激活对话框,要求使用者激活。对机器码右键copy 后,发送给开发小哥,小哥把对应的激活码发给你后,就可以的正常使用软件。一机对一码,把激活码保存好哟!


🔑 step4: 电脑网络设置为全局可连通国际互联网模式。(如果使用的ChatCatsyV1.1 版本,可以忽略此步骤。

🔑 step5: 设置API key


🔑 step6:验证软件服务是否正常

ChatCatsyV1.0 版本验证:(需要做step4步骤的操作)

ChatCatsyV1.1 版本验证:

第三章:软件定价

ChatCatsyV1.0 : 30元/个

ChatCatsyV1.1 : 50元/个

独立账号API秘钥 : 20元/个 (纯手工注册,数量有限!不单独供给!)

远程调试服务:20元/次

1级 2级 3级 4级 5级 6级 7级
正版软件 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.0 ChatCatsyV1.1 ChatCatsyV1.1 ChatCatsyV1.1
独立GPT账号
远程调试
价格 30 元 50元 50元 70元 50元 70元 90元

独立GPT账号-API秘钥 ,包含5美元额度,如何验证:

📌 注意1:全新的独立账号,额度剩余是5美元。

📌 注意2不要用共享账号,会面临随时封号和存在访问竞争,同一时间段,别人能用,你就用不了。隐私泄露!即使我们使用独立账号,提问数据也要不要涉及隐私信息,脱敏后进行知识的问答。

📌 注意3:当你的账号或秘钥,稳定使用后的某天,因不可抗力因素或因为多人使用你的账号,被openai官方封号, 损失自行承担。

📌 联系方式:开发小哥WeChat &qq : 1071235258

ChatGPT翩然起舞,以文本为笔创意无限

zhangtongle阅读(1955)

ChatGPT翩然起舞以文本为笔创意无限   原价198  重磅上新价:118.8
https://edu.51cto.com/course/33827.html

第一部分:ChatGPT基础

在这部分中,你将学习ChatGPT的基本概念和原理,了解自然语言处理的基本技术,以及如何使用ChatGPT进行对话和生成文本。

第二部分:ChatGPT prompts 提示词工程

这部分将教你如何构建有效的ChatGPT提示词,通过合理的提问和指导,引导ChatGPT生成你想要的回答和结果。

第三部分:ChatGPT高级应用

这部分将涵盖一系列高级应用,包括使用AI文本到图像生成器创造你想要的图像,语音处理技术,PPT制作工具,思维导图的制作方法以及视频制作的基本原理和工具。

第四部分:ChatGPT 开发框架和实用工具

在这部分中,你将学习ChatGPT的开发框架和常用实用工具,了解如何进行定制化开发和应用,以满足个人或企业的需求。

第五部分:ChatGPT在自动化办公中的应用

这部分将介绍如何将ChatGPT应用于自动化办公场景,例如自动回复邮件、智能日程安排、自动化报告生成等,提高工作效率和减轻重复性任务的负担。

第六部分:ChatGPT在商业应用中的应用

在这部分中,你将了解如何将ChatGPT应用于商业场景,包括市场调研、客户服务、智能推荐等领域,帮助企业提升竞争力和用户体验。

通过学习这门课程,你将掌握ChatGPT的基础知识和应用技巧,了解如何使用AI技术解决实际问题,并在自动化办公和商业应用中获得成长和优势。课程内容以图文结合的形式呈现,帮助你更好地理解和应用所学知识。

Pandas之read_excel函数的重要性

zhangtongle阅读(1919)

1、普通使用


excel_path = r'某公司销售数据-全国订单明细.xls' # Excel 数据路径
sales_data = pd.read_excel(excel_path) # 返回的DataFrame
sales_data.head(1) # 使用head 获取前1个数据

2、读取指定sheet

excel_sheet

pd.read_excel(excel_path,sheet_name='成绩表') # 读取成绩表

pd.read_excel(excel_path,sheet_name=2) # 读取全国订单明细,读取sheet的索引为2的表

3、指定表头

excel_header

把考勤表的第二行当表头

pd.read_excel(excel_path,sheet_name='考勤表',header=1)

4、只读取表中需要的列

# 通过列名
pd.read_excel(excel_path, usecols=['顾客姓名','订单数量','销售额'])[:2]
顾客姓名 订单数量 销售额
0 李鹏晨 6 261.54
1 王勇民 2 6.00
# 通过Excel 列的标识符。
pd.read_excel(excel_path, usecols="A:E")[:2]
订单号 订单日期 顾客姓名 订单等级 订单数量
0 3 2010-10-13 李鹏晨 低级 6
1 6 2012-02-20 王勇民 其它 2

5、将某列(字段)作为查询的的条件和依据)

# 将订单日期作为查询条件
df = pd.read_excel(excel_path,index_col=1,usecols="A:E")[:2]
df.loc['2011-07-15'] # 查询订单日期2011-07-15的所有数据
订单号 顾客姓名 订单等级 订单数量
订单日期
2011-07-15 32 姚文文 高级 26
2011-07-15 32 姚文文 高级 24

6、将多个字段作为查询条件

# 将订单日期和 订单等级作为查询索引(条件)
df = pd.read_excel(excel_path,index_col=[1,3],usecols="A:E")
df = df.sort_index()  # 需要将索引(查询字段)排序,要不不然会报警告

df.loc['2012-11-15','低级'].reset_index() # 查询日期和订单等级
订单日期 订单号 顾客姓名 订单数量
0 2012-11-15 13346 周雨生 44

7、跳过表中最后无用的数据

skip_footer

# 跳过工资表中的最后7行内容,不读取
pd.read_excel(excel_path,sheet_name='工资表',usecols="A:B",skipfooter=7)

8、指定Excel中的数据类型

# Excel 中salary数字列,夹杂了文字。需要转str,进一步的过滤和处理
df = pd.read_excel(excel_path,sheet_name='工资表',usecols="A:B",skipfooter=7, \
              dtype={'name': str, 'salary': str})

Python-导入模块的最佳实践

zhangtongle阅读(2312)

导入模块的“最佳实践”是什么

通常请勿使用 from modulename import * 。因为这会扰乱 importer 的命名空间,且会造成未定义名称更难以被 Linter 检查出来。

请在代码文件的首部就导入模块。这样代码所需的模块就一目了然了,也不用考虑模块名是否在作用域内的问题。每行导入一个模块则增删起来会比较容易,每行导入多个模块则更节省屏幕空间。

按如下顺序导入模块就是一种好做法:

standard library modules -- e.g. sys, os, argparse, re
third-party library modules (anything installed in Python's site-packages directory) -- e.g. dateutil, requests, PIL.Image
locally developed modules

为了避免循环导入引发的问题,有时需要将模块导入语句移入函数或类的内部。Gordon McMillan 的说法如下:

当两个模块都采用 "import " 的导入形式时,循环导入是没有问题的。
但如果第 2 个模块想从第 1 个模块中取出一个名称("from module import name")并且导入处于代码的最顶层,那导入就会失败。原因是第 1 个模块中的名称还不可用,这时第 1 个模块正忙于导入第 2 个模块呢。

如果只是在一个函数中用到第 2 个模块,那这时将导入语句移入该函数内部即可。当调用到导入语句时,第 1 个模块将已经完成初始化,第 2 个模块就可以进行导入了。

如果某些模块是平台相关的,可能还需要把导入语句移出最顶级代码。这种情况下,甚至有可能无法导入文件首部的所有模块。于是在对应的平台相关代码中导入正确的模块,就是一种不错的选择。

只有为了避免循环导入问题,或有必要减少模块初始化时间时,才把导入语句移入类似函数定义内部的局部作用域。如果根据程序的执行方式,许多导入操作不是必需的,那么这种技术尤其有用。如果模块仅在某个函数中用到,可能还要将导入操作移入该函数内部。请注意,因为模块有一次初始化过程,所以第一次加载模块的代价可能会比较高,但多次加载几乎没有什么花费,代价只是进行几次字典检索而已。即使模块名超出了作用域,模块在 sys.modules 中也是可用的只有为了避免循环导入问题,或有必要减少模块初始化时间时,才把导入语句移入类似函数定义内部的局部作用域。如果根据程序的执行方式,许多导入操作不是必需的,那么这种技术尤其有用。如果模块仅在某个函数中用到,可能还要将导入操作移入该函数内部。请注意,因为模块有一次初始化过程,所以第一次加载模块的代价可能会比较高,但多次加载几乎没有什么花费,代价只是进行几次字典检索而已。即使模块名超出了作用域,模块在 sys.modules 中也是可用的。

解决循环import的方法主要有几种:

1.延迟导入(lazy import)

  即把import语句写在方法或函数里面,将它的作用域限制在局部。
  这种方法的缺点就是会有性能问题。

2.将from xxx import yyy改成import xxx;xxx.yyy来访问的形式

3.组织代码

  出现循环import的问题往往意味着代码的布局有问题。
  可以合并或者分离竞争资源。
  合并的话就是都写到一个文件里面去。
  分离的话就是把需要import的资源提取到一个第三方文件去。
  总之就是将循环变成单向。

PyWin32系列文章-在过去8小时内发现的系统事件

zhangtongle阅读(2299)

Python对Eventlog的win32访问

如果您需要扫描许多服务器的事件日志或根据事件日志进行特定筛选,python的win32evtlogwin32evdlogutil库为您提供了一种有效的方法。

最重要的库是win32evtlog。使用它,您可以通过调用连接到服务器的事件日志。

实例
以下是基本调用:

logtype='System'
hand=win32evtlog.OpenEventLog(server,logtype)

这将返回一个句柄,您可以从该句柄进行调用,例如一个可以提供事件总数的句柄,或者另一个可以检查每个事件的详细信息的句柄。logtype变量设置为要查看的日志类型。默认值为:应用程序、安全性和系统。

掌握句柄后,您可以询问诸如记录数量或特定事件记录之类的信息:

total=win32evtlog.GetNumberOfEventLogRecords(hand)
flags = win32evtlog.EVENTLOG_BACKWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ
events=win32evtlog.ReadEventLog(hand,flags,0)

ReadEventLog返回一些事件对象,这些对象可能不是全部。您需要不断地检查循环,直到ReadEventLog不再返回事件。您可能注意到ReadEventLog有一个flags参数。标志(win32evtlog库中通常提供)指定如何读取事件日志。

下面是一个从ReadEventLog返回的事件中获取数据的简单循环:

for ev_obj in events:

    the_time=ev_obj.TimeGenerated.Format() #'12/23/99 15:54:09'

    evt_id=str(winerror.HRESULT_CODE(ev_obj.EventID))

    computer=str(ev_obj.ComputerName)

    cat=ev_obj.EventCategory

    seconds=date2sec(the_time)

    record=ev_obj.RecordNumber

    msg=str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))

    source=str(ev_obj.SourceName)

我们使用库win32evtlogutil获取事件的实际文本正文。要获取事件的易读日期,需要为事件对象的TimeGenerated部分指定“Format”方法。

win32evtlogutil可以方便地为我们提供事件日志消息的实际文本正文。如果您想根据关闭时间进行排序,这里有一个方便的函数,它使用python的time和regexp库将事件日志的时间格式转换为秒:

import re
import sys

import time
import traceback

import win32con
import win32evtlog
import win32evtlogutil
import winerror

def date2sec(evt_date):
    regexp = re.compile('(.*)\\s(.*)')  # store result in site
    reg_result = regexp.search(evt_date)
    time_res = reg_result.group() # 年月日时分秒
    res = time.strptime(time_res) # 由字符串转换成日期类型
    (mon, day, yr) = res.tm_mon,res.tm_mday,res.tm_year
    (hr, min, sec) = res.tm_hour,res.tm_min,res.tm_sec
    tup = yr, mon, day, hr, min, sec, 0, 0, 0
    sec = time.mktime(tup)
    return sec

flags = win32evtlog.EVENTLOG_BACKWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ

# This dict converts the event type into a human readable form
evt_dict = {win32con.EVENTLOG_AUDIT_FAILURE: 'EVENTLOG_AUDIT_FAILURE',
            win32con.EVENTLOG_AUDIT_SUCCESS: 'EVENTLOG_AUDIT_SUCCESS',
            win32con.EVENTLOG_INFORMATION_TYPE: 'EVENTLOG_INFORMATION_TYPE',
            win32con.EVENTLOG_WARNING_TYPE: 'EVENTLOG_WARNING_TYPE',
            win32con.EVENTLOG_ERROR_TYPE: 'EVENTLOG_ERROR_TYPE'}

computer = 'localhost'  # 本地localhost
logtype = 'System'
begin_sec = time.time()
begin_time = time.strftime('%H:%M:%S  ', time.localtime(begin_sec))
# open event log
hand = win32evtlog.OpenEventLog(computer, logtype)
print(logtype, ' events found in the last 8 hours since:', begin_time)

try:
    events = 1
    while events:
        events = win32evtlog.ReadEventLog(hand, flags, 0)
        for ev_obj in events:
            # check if the event is recent enough
            # only want data from last 8hrs
            the_time = ev_obj.TimeGenerated.Format()
            seconds = date2sec(the_time)
            if seconds < begin_sec - 28800: break
            # data is recent enough, so print it out
            computer = str(ev_obj.ComputerName)
            cat = str(ev_obj.EventCategory)
            src = str(ev_obj.SourceName)
            record = str(ev_obj.RecordNumber)
            evt_id = str(winerror.HRESULT_CODE(ev_obj.EventID))
            evt_type = str(evt_dict[ev_obj.EventType])
            msg = str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))
            print(':'.join([the_time, computer, src, cat, record,evt_id, evt_type, msg[0:15]]))

        if seconds < begin_sec - 28800: break

    win32evtlog.CloseEventLog(hand)

except:
    print(traceback.print_exc(sys.exc_info()))
System  events found in the last 8 hours since: 23:19:40  
Fri Dec  2 23:18:03 2022:zhangtl:Microsoft-Windows-DNS-Client:0:186338:1014:EVENTLOG_WARNING_TYPE:在没有配置的 DNS 服务器响
Fri Dec  2 23:16:28 2022:zhangtl:DCOM:0:186337:10016:EVENTLOG_ERROR_TYPE:<The descriptio
Fri Dec  2 23:14:53 2022:zhangtl:Service Control Manager:0:186336:7036:EVENTLOG_INFORMATION_TYPE:Windows Error R
Fri Dec  2 23:12:53 2022:zhangtl:Service Control Manager:0:186335:7036:EVENTLOG_INFORMATION_TYPE:Windows Error R
Fri Dec  2 23:07:13 2022:zhangtl:Service Control Manager:0:186334:7040:EVENTLOG_INFORMATION_TYPE:Background Inte
Fri Dec  2 23:06:28 2022:zhangtl:DCOM:0:186333:10016:EVENTLOG_ERROR_TYPE:<The descriptio

PyWin32系列文章-递归目录删除和特殊文件

zhangtongle阅读(2146)

Python的win32访问文件属性以启用删除

有时您可能需要执行一些操作,例如删除整个目录树。Python有一些很棒的实用程序可以做到这一点,但具有特殊属性的文件通常无法删除。

为了解决这个问题,您需要使用对SetFileAttributes的win32调用作为普通文件。

C++调用如下所示:

BOOL SetFileAttributes(LPCTSTR lpFileName,DWORD dwFileAttributes);

您为它提供了两个参数,即文件名和特定属性,并返回是否成功。

相应的python调用是:int=win32api。SetFileAttributes(路径名,属性)

唯一的问题是你从哪里得到属性。它包含在非常方便的win32con模块中,特别是win32con.FILEATTRIBUTE*。您可以将文件设置为只读、存档、隐藏等。我们关注的是将其设置为正常,因此我们希望:win32con.file_ATTRIBUTE_normal

下面的示例可能很有用,但当然要小心,因为它会删除很多内容。这是一个递归函数。该示例还使用了os模块中的一些方便的函数。

实例

以下是如何删除目录树的基本示例:


import os

import win32api
import win32con

def del_dir(self, path):
    for file in os.listdir(path):
        file_or_dir = os.path.join(path, file)
        if os.path.isdir(file_or_dir) and not os.path.islink(file_or_dir):
            del_dir(file_or_dir)  # it's a directory reucursive call to function again
        else:
            try:
                os.remove(file_or_dir)  # it's a file, delete it
            except:
                # probably failed because it is not a normal file
                win32api.SetFileAttributes(file_or_dir, win32con.FILE_ATTRIBUTE_NORMAL)
                os.remove(file_or_dir)  # it's a file, delete it
        os.rmdir(path)  # delete the directory here

Pytest全栈自动化测试指南-入门

zhangtongle阅读(2329)

Pytest介绍

Pytest是一个成熟的全功能Python测试工具,可以帮助您编写更好的程序。该pytest框架使编写可读测试变得容易,并且可以扩展以支持应用程序和库的复杂功能测试。pytest需要:Python 3.7+ 或 PyPy3。

Pytest特点

开箱即用.自动发现测试用例简化断言语句,统一为assert丰富的插件架构,超过 800 多个外部插件具有灵活的扩展性和方便的参数化方法

安装&使用

$ pip install  pytest
$ pytest --version
pytest 7.1.2

命名规则&断言

  1. 模块:test_.py 或_test.py。
  2. 函数:test*。
  3. 类:Test*,测试类不能有init函数。
  4. 断言:assert ,支持所有python的布尔表达式

用例执行顺序

  1. 在包含用例的项目根路径下(root-dir)执行:pytest -v
  2. 目录和py文件:按照ascii码排序方式,进行文件递归顺序收集和运行
  3. py文件中:按照代码从上到下
  4. 验证执行顺序:pytest --collect-only

命令行选项

pytest自动化测试

assert 布尔表达式

  • [x] 比较运算符:【>】【<】【<=】【>=】【==】【!=】
    例如:assert actual == expected

  • [x] 身份和成员运算符: 【is】、【is not】、【in】、【not in】
    例如: assert expected in actual

  • [x] 逻辑运算符和布尔函数:【not】【and】【or】【startswith()】
    例如 :assert not expected
    例如 :assert version.startswith("3.8")

待测student功能

# ---------------------------------student.py--------------------------------------
# 以字典的形式返回学生的姓名和成绩
def student_score():
    return {'小明': 99, '小红': 100}

# 以列表的形式返回学生的姓名
def student_name():
    return ['小明', '小红']

编写pass 与fail 用例

# ---------------------------------test_01_pass_fail.py---------------------------
# 这是通过用例
def test_pass():
    # 期望值
    expected = 1
    # 实际值
    actual = 1
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是失败,不通过用例
def test_fail():
    # 期望值
    expected = 2
    # 实际值
    actual = 3
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# ---------------------------------test_02_datatype.py----------------------------
from btest.Day1.student import student_score, student_name

# 这是student_score的验证全数据等式用例
def test_student_score():
    # 期望值
    expected = {'小红': 100, '小明': 99}
    # 实际值
    actual = student_score()
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是student_score 的验证部分数据等式用例
# 验证小红是否等于100,是:pass 、否:fail
def test_student_score_other():
    # 期望值
    expected = 100
    # 实际值
    actual = student_score()['小红']
    # 通过(实际值)跟(预期值)进行相等比较,相等通过,不相等报错
    assert actual == expected

# 这是student_name 的包含用例:
# 验证小明是否在学生姓名列表中,是:pass(通过), 否:fail(失败)
def test_student_name():
    # 期望值
    expected = '小明123123'
    # 实际值
    actual = student_name()
    # 通过判断(预期数据)是否在实际数据中,在:pass,不在:fail
    assert len(actual) == 2
    assert expected in actual

多断言

# ---------------------------------test_03_many_assert.py-------------------------
# 安装: pip install pytest-assume -i https://pypi.douban.com/simple
from pytest_assume.plugin import assume

from btest.Day1.student import student_score

def test_student_score_hard():
    actual = student_score()

    with assume: # 实际数据类型是否跟预期数据类型一致。
        assert isinstance(actual, dict)

    with assume: # 实际的数据长度是否跟预期长度相同
        assert len(actual) == 3

    with assume: # 预期数据是否在实际数据内
        assert '小红123123' in actual

    with assume: # 实际数据是否等于预期数据
        assert actual['小红'] == 60

自定义异常信息

# ---------------------------------test_04_custom_fail.py-------------------------
import pytest
from pytest_assume.plugin import assume

from btest.Day1.student import student_name

def test_student_name_hard_custom_fail():
    actual = student_name()
    with assume:  # 实际的数据长度是否跟预期长度相同
        assert len(actual) == 3, \
            f"实际数据长度:{len(actual)} 与预期数据长度:{3}不相同!!"

    with assume:  # 预期数据是否在实际数据内
        assert '小红' in actual, \
            f"预期数据:{'小红'}没在实际数据中:{actual}!!"

    if '小乐' not in actual:
        pytest.fail(f"预期数据:小乐,没有在实际数据{actual}中")

处理异常

# ---------------------------------test_05_exceptions.py--------------------------
import pytest

from btest.Day1.student import student_score

# 通用try/finally 处理用例异常
def test_student_score_error():
    actual = student_score()
    try:
        actual['小红'] = actual['小红'] + '10'
    except:
        pass
    finally:
        assert '小乐' in actual, "小乐没有在学生成绩表里!!"

# pytest用例异常处理
def test_student_score_raise():
    actual = student_score()
    with pytest.raises(Exception):  # 更具可读性且不易出错。
        actual['小红'] = actual['小红'] + '10'
        # assert '小乐' in actual # 不会执行
    # 会执行
    assert '小乐' in actual, \
        f" 预期数据:小乐,没有在实际数据中{actual}!!"

# ---------------------------------test_06_get_error.py---------------------------
"""
1、获取用例的所在的模块、
2、获取用例的名称、
3、获取用例的具体错误信息。
"""

import inspect  # 从实时 Python 对象中获取有用的信息

import pytest

# python-inspect 捕获详细异常信息
def test_inspect_info():
    # 期望值为 模块名::用例名::错误信息
    expected = 'test_06_get_error::test_inspect_info::division by zero'

    with pytest.raises(Exception) as exc_info:
        c = 2 / 0

    # 获取错误文本:exc_info.value.args[0]
    # 如获取错误类型:exc_info.type
    error_info = exc_info.value.args[0]  # 获取用例具体错误信息

    module_name = inspect.getmodulename(__file__)  # 获取用例所在模块
    method_name = inspect.stack()[0][3]  # [0][3]获取用例名字,[1][4][0]获取用例名字和参数

    actual = f"{module_name}::{method_name}::{error_info}"
    assert actual == expected

# Pytest内置功能捕获异常信息
def test_get_raises(request):
    # 期望值为 模块名::用例名::错误信息
    expected = 'test_06_get_error::test_get_raises::division by zero'

    with pytest.raises(Exception) as exc_info:
        c = 2 / 0

    error_info = exc_info.value.args[0]

    module_name = request.module.__name__.split('.')[-1]  # 获取模块 包名.test_06xxx
    method_name = request.function.__name__  # 获取用例名字
    actual = f"{module_name}::{method_name}::{error_info}"
    assert actual == expected

数据类

Dataclass这个模块提供了一个类装饰器和一些函数,用于自动添加生成的 special method,例如 init() 和 repr() 到用户定义的类。 它最初描述于 PEP 557 .

对标准库的补充,称为数据类。可以将数据类视为“具有默认值的可变命名元组”

数据类使用普通的类定义语法,你可以自由地使用继承、元类、文档字符串、用户定义的方法、类工厂和其他 Python 类特性.

装饰器: https://www.ztloo.com/2021/11/06/decorators/

Python术语对照社区文档: https://docs.python.org/zh-cn/3/glossary.html?highlight=decorator

special method(特殊方法) :https://docs.python.org/zh-cn/3/glossary.html#term-special-method

PEP 557(Python 增强建议) :https://www.python.org/dev/peps/pep-0557

标准库:https://docs.python.org/zh-cn/3/library/index.html

命名元组: https://docs.python.org/zh-cn/3/library/collections.html?highlight=namedtuple

# ---------------------------------face_to_object.py------------------------------
from dataclasses import asdict, dataclass, astuple, replace

# https://docs.python.org/3/library/dataclasses.html?highlight=dataclass#module-dataclasses

@dataclass
class GirlFriend:
    # 节省了__init__函数
    name: str
    age: int
    height: int = 170  # cm
    weight: int = 50  # kg

    @classmethod
    def from_dict(cls, d):
        return GirlFriend(**d)

    def to_dict(self):
        return asdict(self)

    def to_tuple(self):
        return astuple(self)

    def update(self, **changes):
        return replace(self, **changes)

if __name__ == '__main__':
    # 把字典转行成类对象
    ym_dict = {'name': '杨幂', 'age': 18, 'height': 170, 'weight': 68}
    ym = GirlFriend.from_dict(ym_dict)
    print('我是类对象型杨幂', ym)

    # 把类对象转化成字典
    ym_dict = ym.to_dict()
    print('我是字典型杨幂:', ym_dict)

    # 把类对象转化成元组
    ym_tuple = ym.to_tuple()
    print(f'我是元组型杨幂:{ym_tuple}')

    # 把杨幂修改成刘亦菲
    lyf = ym.update(name='刘亦菲', age=22)
    print(f'我是刘亦菲:{lyf}')

自定义辅助断言函数

import pytest

from btest.Day2.face_to_object import GirlFriend

def assert_identical(gf_1, gf_2):
    if gf_1.name != gf_2.name:
        pytest.fail(f"name不匹配. {gf_1.name} != {gf_2.name}")

def test_identical():
    gf_1 = GirlFriend("刘亦菲", 18, 170, 60)
    gf_2 = GirlFriend("刘亦菲", 18, 170, 60)
    assert_identical(gf_1, gf_2)

更多案例,更多内容,请点击: http://weike.fm/KzXbA994f

python的__get__方法看这一篇就足够了

zhangtongle阅读(2144)

没有get普通类的属性访问

class TestMain:
    def __init__(self):
        print('TestMain:__init__')
        self.a = 1

if __name__ == '__main__':
    t = TestMain()
    print(t.a)

#输出
TestMain:__init__
1

如果访问一个不存在的属性:

if __name__ == '__main__':
    t = TestMain()
    print(t.a)
    print(t.b) # 访问了一个不存在的属性

# 输出:
TestMain:__init__
Traceback (most recent call last):
print(t.b)
AttributeError: 'TestMain' object has no attribute 'b'

添加getattr 函数,解决上述问题

class TestMain:
    def __init__(self):
        print('TestMain:__init__')
        self.a = 1

    def __getattr__(self, item):
        print('TestMain:__getattr__')
        return 2

if __name__ == '__main__':
    t = TestMain()
    print(t.a)
    print(t.b)

# 输出:
TestMain:__init__
1
TestMain:__getattr__
2

说明:我们仍然访问了一个本来不存在的t.b,为什么这里没有报错呢,因为我们定义了getattr函数,而且让它直接返回了2,也就是说,如果定义了这个函数后,访问不存在的属性,会自动调用这个函数作为返回值。

接下来_getattribute__函数:

class TestMain:
    def __init__(self):
        print('TestMain:__init__')
        self.a = 1

    def __getattr__(self, item):
        print('TestMain:__getattr__')
        return 2

    def __getattribute__(self, item):
        print('TestMain:__getattribute__')
        return 3

if __name__ == '__main__':
    t = TestMain()
    print(t.a)
    print(t.b)

# 输出结果
TestMain:__init__
TestMain:__getattribute__
3
TestMain:__getattribute__
3

可以看到,无论是访问存在的t.a还是不存在的t.b,都访问到了getattribute这个函数,也就是说,只要定义了这个函数,那么属性的访问,都会走到这个函数里面。

我们知道只要定义了getattribute函数,就肯定执行这个函数来获取属性,这次我们增加了判断如果访问c这个属性,我们抛出异常,最后的结果是:

TestMain:__init__
TestMain:__getattribute__
3
TestMain:__getattribute__
3
TestMain:__getattribute__
TestMain:__getattr__
2

也就是说,如果getattribute抛出了AttributeError异常,那么会继续访问getattr函数的。

总结:

  1. 如果定义了getattribute,那么无论访问什么属性,都是通过这个函数获取,包括方法,t.f()这种也是访问的这个函数,此时这个函数应该放回一个方法,如果像例子中,仍然返回一个数字,你会获得一个TypeError: 'int' object is not callable错误

  2. 只要定义了getattribute方法,不管你访问一个存在的还是不存在的属性,都由这个方法返回,比如访问t.a,虽然a存在,但是只要定义了这个访问,那么就不是访问最开始的a了

  3. 如果getattribute抛出了AttributeError异常,并且定了了getattr函数,那么会调用getattr这个函数,不论这个属性到底是不是存在

  4. 也就是说属性访问的一个大致优先级是:getattribute > getattr > dict


get函数

上面说了getattributegetattr,这里单独说一下get,因为这个涉及到其它的概念,就是描述器(Descriptor)

一个类只要实现了getsetdelete中任意一个方法,我们就可以叫它描述器(descriptor)。如果只定义了get我们叫非资料描述器(non-data descriptor),如果setdelete任意一个/或者同时出现,我们叫资料描述器(data descriptor)。

首先明确一点,拥有这个方法的类,应该(也可以说是必须)产生一个实例,并且这个实例是另外一个类的类属性(注意一定是类属性,通过self的方式产生就不属于get范畴了)。

也就是说拥有这个方法的类,那么它的实例应该属于另外一个类/对象的一个属性。 直接看代码吧:


class TestDes:
    def __get__(self, instance, owner):
        print(instance, owner)
        return 'TestDes:__get__'

class TestMain:
    des = TestDes()

if __name__ == '__main__':
    t = TestMain()
    print(t.des)
    print(TestMain.des)

# 输出:
<__main__.TestMain object at 0x0000022563D5D3C8> <class '__main__.TestMain'>
TestDes:__get__
None <class '__main__.TestMain'>
TestDes:__get__

其中TestDes定义了get方法,在TestMain中,定义了一个类属性des,是TestDes的一个实例,我们访问t.des或者TestMain.des的时候访问的就是访问了TestDes的get方法。

其中,get方法的第一个参数是实际拥有者的实例,如果没有则为None,第二个参数是实际所属的类。

看一下下面的代码:

class TestDes:
    def __get__(self, instance, owner):
        print(instance, owner)
        return 'TestDes:__get__'

class TestMain:
    def __init__(self):
        self.des = TestDes()

if __name__ == '__main__':
    t = TestMain()
    print(t.des)
    # print(TestMain.des) #很明显这里会报错

我们通过init来产生了一个实例的des属性,这时候,print(t.des)访问的就不是get函数了,实际打印结果是:

<__main__.TestDes object at 0x00000165A77ECCF8>

也就是当成一个普通的实例来处理的。

非资料描述器,也就是只有get,不管是类还是实例去访问,默认都获得的是get的返回值,但是,如果中间有任何一次重新赋值,那么,这个实例获得的是新的值(对象),已经和原来的描述器完全脱离了关系
资料描述器,比如有set方法,后期通过实例对描述器进行赋值,那么访问的是set,并且永远关联起来。但是如果通过修改类属性的方式复制,那么也会被重新获取新的值(对象)。

看下面的代码:

class TestDes:
    def __get__(self, instance, owner):
        print('TestDes:__get__', instance, owner)
        return 'TestDes:__get__'

class TestMain:
    des = TestDes()

if __name__ == '__main__':
    t = TestMain()
    print(t.des)
    print(TestMain.des)

    print()

    t.des = 1
    print(t.des)
    print(TestMain.des)

    print()

    TestMain.des = 1
    print(t.des)
    print(TestMain.des)

上面是一个非资料描述器,打印结果是:

TestDes:__get__ <__main__.TestMain object at 0x000002C9BCCF0080> <class '__main__.TestMain'>
TestDes:__get__
TestDes:__get__ None <class '__main__.TestMain'>
TestDes:__get__

1
TestDes:__get__ None <class '__main__.TestMain'>
TestDes:__get__

1
1

具体根据上面的描述行为进行分析,就可以得出结果了。

我们在看一下资料描述器:

class TestDes:
    def __get__(self, instance, owner):
        print('TestDes:__get__', instance, owner)
        return 'TestDes:__get__'

    def __set__(self, instance, value):
        print('TestDes:__set__', instance, value)

# 其它代码没有修改

打印结果如下

TestDes:__get__ <__main__.TestMain object at 0x000002140A46D390> <class '__main__.TestMain'>
TestDes:__get__
TestDes:__get__ None <class '__main__.TestMain'>
TestDes:__get__

TestDes:__set__ <__main__.TestMain object at 0x000002140A46D390> 1
TestDes:__get__ <__main__.TestMain object at 0x000002140A46D390> <class '__main__.TestMain'>
TestDes:__get__
TestDes:__get__ None <class '__main__.TestMain'>
TestDes:__get__

1
1

总结

  1. getattributegetattr用于实例访问属性使用,拥有get方法的类是只能其实例属于类属性的时候生效
  2. 只要有getattribute,任何属性访问都是这个的返回值,以下都是在getattribute不存在或者有AttributeError异常发生的情况下描述的
  3. 访问不存在的属性,getattr生效
  4. 访问存在的属性,如果是描述器,描述器生效
  5. 如果通过实例对描述器进行赋值操作,又有资料和非资料描述器的区分,如果定义了set,那么此方法生效,并且仍然是原始的资料描述器,否则被赋值为新对象
  6. 描述器赋值如果是通过类的属性方式赋值,而不是类的实例方式赋值,描述器失效
  7. 针对描述器的说明: 描述器是被getattribute调用的,如果重写了这个方法,将会阻止自动调用描述器,资料描述器总是覆盖了实例的dict, 非资料描述器可能覆盖实例的dict

30个常用的Python代码片段

zhangtongle阅读(2240)

例子1:检查列表中的所有元素是否相等。

def all_equal(lst):
    return lst[1:] == lst[:-1]

# 使用例子
all_equal([1, 2, 3, 4, 5, 6])  # False
all_equal([1, 1, 1, 1])  # True

例子2:检查列表中所有的值是否唯一

def all_unique(lst):
    return len(lst) == len(set(lst))

# 参考案例
x = [1, 2, 3, 4, 5, 6]
y = [1, 2, 2, 3, 4, 5]
all_unique(x)  # True
all_unique(y)  # False

例子3:根据元素对应的布尔值,过滤为2组

def bifurcate(lst, filters):  # lst:列表  filter:依据的过滤内容
    return [
        [x for i, x in enumerate(lst) if filters[i] == True],
        [x for i, x in enumerate(lst) if filters[i] == False]
    ]

# 使用案例
bifurcate(['beep', 'boop', 'foo', 'bar'], [True, True, False, True])
# 输出结果: [ ['beep', 'boop', 'bar'], ['foo'] ]

例子4:根据函数将值拆分为两个组,该函数指定输入列表中的元素属于哪个组。


def bifurcate_by(lst, fn):
    return [
        [x for x in lst if fn(x)],
        [x for x in lst if not fn(x)]

bifurcate_by(['beep', 'boop', 'foo', 'bar'], lambda x: x[0] == 'b')
# 输出结果: [ ['beep', 'boop', 'bar'], ['foo'] ]

例子5:将列表分成较小的指定大小的列表。

'''
使用list()和range()创建所需的列表size。
map()在列表上使用并用给定列表的拼接填充它。最后,返回使用创建列表。
'''

from math import ceil

def chunk(lst, size):
    return list(
        map(lambda x: lst[x * size:x * size + size],
            list(range(0, ceil(len(lst) / size)))))

# 使用案例
chunk([1, 2, 3, 4, 5], 2)
# 输出结果:[[1,2],[3,4],5]

例子6:从列表中删除falsey值。

例如 使用filter()过滤掉falsey值(False,None,0和"")。


def compact(lst):
    return list(filter(bool, lst))

# 使用案例
compact([0, 1, False, 2, '', 3, 'a', 's', 34])
#  输出结果
[ 1, 2, 3, 'a', 's', 34 ]

例子7:根据给定函数对列表元素进行分组,并返回每个组中元素的数量


def count_by(arr, fn=lambda x: x):
    key = {}
    for el in map(fn, arr):
        key[el] = 0 if el not in key else key[el]
        key[el] += 1
    return key

# 使用
from math import floor
count_by([6.1, 4.2, 6.3], floor)
# 输出结果
{4: 1, 6: 2}

count_by(['one', 'two', 'three'], len)
# 输出结果
{3: 2, 5: 1}

例子7:计算列表中值的出现次数


def count_occurrences(lst, val):
    return len([x for x in lst if x == val and type(x) == type(val)])

# 使用
count_occurrences([1, 1, 2, 1, 2, 3], 1)  
# 输出结果
3

例子8:深度压扁列表


'''
使用递归。定义一个函数,spread它使用列表中的每个元素list.extend()或
其中的任何list.append()元素来展平它。
使用list.extend()空列表和spread函数来展平列表。递归地展平作为列表的每个元素。

'''

def spread(arg):
    ret = []
    for i in arg:
        if isinstance(i, list):
            ret.extend(i)
        else:
            ret.append(i)
    return ret

def deep_flatten(lst):
    result = []
    result.extend(
        spread(list(map(lambda x: deep_flatten(x) if type(x) == list else x, lst))))
    return result

deep_flatten([1, [2], [[3], 4], 5])  # [1,2,3,4,5]

例子9:返回两个iterables之间的差异。

def difference(a, b):
    _b = set(b)
    return [item for item in a if item not in _b]

difference([1, 2, 3], [1, 2, 4])  # [3]

例子10、将提供的函数应用于两个列表元素后,返回两个列表之间的差异。

def difference_by(a, b, fn):
    _b = set(map(fn, b))
    return [item for item in a if fn(item) not in _b]

from math import floor

difference_by([2.1, 1.2], [2.3, 3.4], floor)  
# [1.2]
difference_by([{'x': 2}, {'x': 1}], [{'x': 1}], lambda v: v['x']) 
# [ { x: 2 } ]

例子11、通过函数判断,列表是否满足 lambda表达式,满足的true,不满足的False。

def every(lst, fn=lambda x: not not x):
    for el in lst:
        if not fn(el):
            return False
    return True

every([4, 2, 3], lambda x: x > 1)  # True
every([2, 2, 3])  # True

例子12、返回列表中的每个第n个元素

def every_nth(lst, nth):
    return lst[1::nth]

every_nth([1, 2, 3, 4, 5, 6], 2)  # [ 2, 4, 6 ]

例子13、过滤掉列表中的非唯一值。

def filter_non_unique(lst):
    return [item for item in lst if lst.count(item) == 1]

filter_non_unique([1, 2, 2, 3, 4, 4, 5])  # [1, 3, 5]

例子14、根据给定的函数对列表的元素进行分组。

def group_by(lst, fn):
    groups = {}
    for key in list(map(fn, lst)):
        groups[key] = [item for item in lst if fn(item) == key]
    return groups

import math
group_by([6.1, 4.2, 6.3], math.floor)  
# {4: [4.2], 6: [6.1, 6.3]}

例子15、列表中是否存在重复值,


def has_duplicates(lst):
    return len(lst) != len(set(lst))

x = [1, 2, 3, 4, 5, 5]
y = [1, 2, 3, 4, 5]
has_duplicates(x)  # True
has_duplicates(y)  # False

例子16:返回列表的头部。


def head(lst):
    return lst[0]

head([1, 2, 3])  # 1

例子17:返回列表中除最后一个元素之外的所有元素。

def initial(lst):
    return lst[0:-1]

initial([1, 2, 3])
# [1,2]

例子18:初始化给定宽度和高度以及值的2D列表。

def initialize_2d_list(w, h, val=None):
    return [[val for x in range(w)] for y in range(h)]
initialize_2d_list(2, 2, 0)  # [[0,0], [0,0]]

例子19: 初始化包含指定范围内的号码,其中的列表start和end已包括其共同差step。

def initialize_list_with_range(end, start=0, step=1):
    return list(range(start, end + 1, step))

initialize_list_with_range(5)  # [0, 1, 2, 3, 4, 5]
initialize_list_with_range(7, 3)  # [3, 4, 5, 6, 7]
initialize_list_with_range(9, 0, 2)  # [0, 2, 4, 6, 8]

例子20、使用指定的值初始化并填充列表。

def initialize_list_with_values(n, val=0):
    return [val for x in range(n)]

initialize_list_with_values(5, 2)  # [2, 2, 2, 2, 2]

例子21、返回两个列表中存在的元素列表。

def intersection(a, b):
    _b = set(b)
    return [item for item in a if item in _b]

intersection([1, 2, 3], [4, 3, 2])  # [2, 3]

例子22、 将提供的函数应用于两个列表元素后,返回两个列表中存在的元素列表。


def intersection_by(a, b, fn):
    _b = set(map(fn, b))
    return [item for item in a if fn(item) in _b]

from math import floor
intersection_by([2.1, 1.2], [2.3, 3.4], floor)
# [2.1]

例子23、返回列表中的最后一个元素

def last(lst):
    return lst[-1]

last([1, 2, 3])  # 3

24、获取具有length属性的任意数量的可迭代对象或对象,并返回最长的属性

def longest_item(*args):
    return max(args, key=len)

longest_item('this', 'is', 'a', 'testcase')  # 'testcase'
longest_item([1, 2, 3], [1, 2], [1, 2, 3, 4, 5])  # [1, 2, 3, 4, 5]
longest_item([1, 2, 3], 'foobar')  # 'foobar'

25、返回n提供列表中的最大元素

def max_n(lst, n=1):
    return sorted(lst, reverse=True)[:n]

max_n([1, 2, 3])  # [3]
max_n([1, 2, 3], 2)  # [3,2]

26、返回n提供列表中的最小元素

def min_n(lst, n=1):
    return sorted(lst, reverse=False)[:n]

min_n([1, 2, 3])  # [1]
min_n([1, 2, 3], 2)  # [1,2]

27、如果提供的函数返回True列表中的至少一个元素,True否则。

def none(lst, fn=lambda x: not not x):
    for el in lst:
        if fn(el):
            return False
    return True

none([0, 1, 2, 0], lambda x: x >= 2)  # False
none([0, 0, 0])  # True

28、将指定数量的元素移动到列表的末尾。

def offset(lst, offset):
    return lst[offset:] + lst[:offset]

offset([1, 2, 3, 4, 5], 2)  # [3, 4, 5, 1, 2]
offset([1, 2, 3, 4, 5], -2)  # [4, 5, 1, 2, 3]

29、从数组中返回一个随机元素。

from random import randint

def sample(lst):
    return lst[randint(0, len(lst) - 1)]
sample([3, 7, 9, 11])  # 9

30、随机化列表值的顺序,返回一个新列表。

from copy import deepcopy
from random import randint

def shuffle(lst):
    temp_lst = deepcopy(lst)
    m = len(temp_lst)
    while (m):
        m -= 1
        i = randint(0, m)
        temp_lst[m], temp_lst[i] = temp_lst[i], temp_lst[m]
    return temp_lst

foo = [1, 2, 3]
shuffle(foo)  # [2,3,1] , foo = [1,2,3]

31 、返回两个列表中存在的元素列表。


def similarity(a, b):
    return [item for item in a if item in b]

similarity([1, 2, 3], [1, 2, 4])  # [1, 2]

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715
error: Sorry,暂时内容不可复制!