commit a7ce0026f34520d1174c81be96624ea30ca617e5 Author: floraachy Date: Thu Mar 12 17:12:39 2020 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..367a807 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.cache/ +__pycache__/ +*.pyc +/chrometest.py +/demo.py +/run.py +/.idea/ +/venv/ +framework/__pycache__/ +pom/__pycache__/ +pom/elements/__pycache__/ +pom/pages/__pycache__/ +screenshots/ +testcase/__pycache__/ +/report/html/*.html +/report/logs/*.log \ No newline at end of file diff --git a/python27Class/LearningNotesTXT/Python/flora_0204_homework.txt b/python27Class/LearningNotesTXT/Python/flora_0204_homework.txt new file mode 100644 index 0000000..73fa4ee --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0204_homework.txt @@ -0,0 +1,104 @@ + +================================= + HomeWork +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + + +一、下面那些不能作为变量? +1、find 2、 _num 3、7val 4、add. 5、def +6、pan 7、-print 8、open_file 9、FileName 10、9prints +11、INPUT 12、ls 13、user^name 14、list1 15、str_ +16、_888 17、is 18、true 19、none 20、try + +答: 不能作为变量的是:7val, add., def, -print, 9prints, user^name, is, try + + +二、请描述一下变量的命名规范,(简单题) + +变量名命名的规范: + + 变量只能包含字母、数字和下划线 + 变量名可以字母或下划线开头,不能以数字开头 + 变量名不能包含空格,但可以使用下划线来分隔其中的单词 + 不能将python关键字和函数名作为变量名 + 变量名应该见名知意 + + + +三、python如何如何添加注释 +单行注释用井号(#)标识 +多行注释用三引号(""")标识 + + + +四、把学的python基本语法,总结成笔记(以后每次课都要整理) +======================================================= + +python的基本语法 +------------------------------------------------------- + +输出函数:print + +示例:print("hello world!") + + +输入函数:input 控制台输入内容 + +示例:input("请输入:") + + +打印python关键字(35个):python内置的一些具有特定功能的单词 + +import keyword +print(keyword.kwlist) + +['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] + + +注释: + + 单行注释用井号(#)标识,快捷键Ctrl+/ 注释是不会换行的 + 多行注释(文档注释/文档字符型串)用三引号(""" )标识 对整个文件的内容进行相关的注释说明 + 注意:注释的目的是阐述代码要做什么,以及如何做 + + +变量名命名的规范: + + 变量只能包含字母、数字和下划线 + 变量名可以字母或下划线开头,不能以数字开头 + 变量名不能包含空格,但可以使用下划线来分隔其中的单词 + 不能将python关键字和函数名作为变量名 + 变量名应该见名知意(不推荐使用拼音) + + +变量名命名的风格: + + 下划线命名(推荐):如果变量由多个单词组成,单词之间用下划线连接,如name_max + 小驼峰命名(不推荐):如果变量由多个单词组成,第二个单词开始首字母大写,如nameMin + 大驼峰命名(不推荐):如果变量由多个单词组成, 每个单词首字母大写,如NameMax + + +扩展: + +常量命名:纯大写字母(推荐) 常量是不变的,如圆周率 + + +标识符: + + 凡是我们自己取得名字都是标识符 + 标识符包括变量名,函数名,类名,文件名(模块名),项目名 + + +数值: + + 整数,如a = 100 + 小数(浮点数), 如b = 3.44 + + +字符串:引号引起来的一串文字 + +示例:str = 'hello' + +======================================================= diff --git a/python27Class/LearningNotesTXT/Python/flora_0206_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0206_notes.txt new file mode 100644 index 0000000..24f00ee --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0206_notes.txt @@ -0,0 +1,66 @@ +================================= + HomeWork +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******Python中常见的数据类型****** +数值类型数据: +1. 整数(int),例如a = 100 +2. 小数(float)(浮点数), 例如 b = 2.3 +3. 布尔值(bool: True, False), 例如c= True, d = False + +内置函数type():可以用来查看数据的类型 + + +******Python中的运算符****** +1. 算术运算符: + - * / //(向下取整) %(取余) **(幂运算) +2. 比较运算符:== != > >= < <= 返回的是True或False +3. 赋值运算符:= += -= *= /= *= +示例: a += 1 相当于a = a + 1 +4. 逻辑运算符(用来比较2个条件):and(与) or(或) not(非) 返回的是True或False +and:所有条件都成立返回True,否则返回False。一假为假, 真真为真。 +or:只要有一个条件成立返回True,条件都不成立返回False。一真为真,假假为假。 +not: 取反。原来是True,返回False; 原来是False,返回True。 +5. 身份运算符(后面学) +6. 成员运算符(后面学) + + +******python中的内置随机函数random****** +random.random():随机生成一个0-1之间的浮点数;生成的小数范围是左闭右开,包含0,不包含1。 +random.randint():生成指定范围的整数;包含起始位置和终止位置的值。 +random.uniform():生成指定范围的浮点数;闭区间或者左闭右开。 + + +import random +number = random.random() +number1 = random.randint(0, 100) + +******字符串类型***** +1. 字符串可以通过单引号,双引号,三引号来表示。 +2. 单引号和双引号没有区别。 +3. 三引号可以用来表示多行字符串。 + +示例: +str1 = '单引号' +str2 = "双引号" +str3 = """三双引号""" +str3 = '''三单引号 +三单引号 +''' + +******数据类型转换***** +整数和浮点数转换为字符串:使用str +字符串和浮点数转换为整数:使用int +整数和字符串转换为浮点数:使用float +整数和浮点数,字符串转换为布尔类型:bool; + +注意点: +使用字符串转换为int或float时,字符串的内容必须是数字(不能有字母和符号) +整数和浮点数转布尔值,只要不是0,返回的布尔值都是True,否则是False。 +字符串转布尔值,空字符串(引号中没有任何内容,包括空格或者其他标点符号)返回的布尔值是False,其他都是True。 + + + +扩展: +按编码规范格式化代码的快捷键(pycharm):Ctrl + Alt + L \ No newline at end of file diff --git a/python27Class/LearningNotesTXT/Python/flora_0208_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0208_notes.txt new file mode 100644 index 0000000..8e9fd93 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0208_notes.txt @@ -0,0 +1,202 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******字符串拼接****** +1. 通过+对字符串进行拼接 +示例: +str1 = 'python' +str2 = 'hello' +print(str1 + str2) # 输出结果:pythonhello +# 此种方法输出会在中间加空格 +print(str1, str2) # 输出结果:python hello + +2. 使用字符串的join方法进行拼接 +示例: +str1 = 'python' +str2 = 'hello' +j = '---' +str3 = j.join((str1, str2)) +print(str3) # 输出结果:python---hello + +或者 +str1 = 'python' +str2 = 'hello' +str3 = ' '.join((str1, str2)) +print(str3) # 输出结果:python hello + +或者 +str1 = 'python' +str2 = ' '.join(str1) +print(str2) # 输出结果:p y t h o n + +******字符串格式化输出****** +1. format格式化输出(常用方式,必须掌握) +示例: +str1 = '今天收到{}, 交来{}{}。开此收据为凭证。' +str2 = str1.format('flora', '学杂费', 666) +print(str2) # 输出结果: 今天收到flora, 交来学杂费666。开此收据为凭证。 +或: +print('今天收到{}, 交来{}{}。开此收据为凭证。'.format('flora', '学杂费', 666)) + +通过索引来控制填充的位置: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = input('请输入金额:') +print('今天收到{2}, 交来{1}费用{0}。开此收据为凭证。'.format(money, info, name)) + +保留指定小数位数: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = float(input('请输入金额:')) +print('今天收到{}, 交来{}费用${:.2f}。开此收据为凭证。'.format(name, info, money)) + +指定占位的字符串长度: +# 默认左对齐 +print('python:{:10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python:123 AAAAAAAAAAAAAAA + +# 左对齐 +print('python:{:<10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python:123 AAAAAAAAAAAAAAA + +# 右对齐 +print('python:{:>10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python: 123AAAAAAAAAAAAAAA + +# 居中对齐 +print('python:{:^10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python: 123 AAAAAAAAAAAAAAA + +指定内容填充: +# 左对齐,以*填充 +print('python:{:*<10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:123*******AAAAAAAAAAAAAAA + +# 右对齐,以-填充 +print('python:{:->10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:-------123AAAAAAAAAAAAAAA + +# 居中对齐,以@填充 +print('python:{:@^10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:@@@123@@@@AAAAAAAAAAAAAAA + +百分比显示效果: +print('百分比:{:.2%}'.format(0.89)) +# 输出结果:百分比:89.00% + +2. 传统的%格式化输出 +%s:万能占位符,可以接收任意类型的数据。 +%d:数值占位符,以整数的形式显示。 +%f: 数值占位符,以小数的形式显示。 + +示例: +print('今天收到%s, 交来%s%d。开此收据为凭证。' % ('flora', '学杂费', 666.98)) +# 输出结果: 今天收到flora, 交来学杂费666。开此收据为凭证。 + +print('今天收到%s, 交来%s%f。开此收据为凭证。' % ('flora', '学杂费', 666)) +# 输出结果: 今天收到flora, 交来学杂费666.000000。开此收据为凭证。 + +print('今天收到%s, 交来%s%.2f。开此收据为凭证。' % ('flora', '学杂费', 666.909090)) +# 输出结果:今天收到flora, 交来学杂费666.91。开此收据为凭证。 + +3. F表达式格式化输出 +示例: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = input('请输入金额:') +print(F'今天收到{name}, 交来{info},{money}。开此收据为凭证。') + +******字符串转义****** +反斜杠\表示转义 +\t:制表符(tab键) +\n:换行符 +\\:表示1个反斜杠\ +示例: +print('python\thello') +# 输出结果:python hello + +print('python2\nhello2') +# 输出结果: +python2 +hello2 + +关闭字符串转义:r防转义 +print(r'python\thello') +# 输出结果:python\thello + +print(r'python2\nhello2') +# 输出结果:python2\nhello2 + +******字符串的常见操作方法****** +1. count查找字符串中某个字符串的个数 +示例: +print('123aa123bb123cc123dd'.count('123')) +# 输出结果:4 + +2. find查找字符串中某个字符串出现的第一个下标(索引)位置 +示例: +print('123aa123bb123cc123dd'.find('aa')) +# 输出结果:3 + +3. replace替换字符串中的某个字符串,默认替换所有 +示例: +print('123aa123bb123cc123dd'.replace('123', '*')) +# 输出结果:*aa*bb*cc*dd + +# 可控制替换的次数 +print('123aa123bb123cc123dd'.replace('123', '*', 1)) +# 输出结果:*aa123bb123cc123dd + +4. upper将字符串中的小写字母变成大写字母 +示例: +print('Hello World 132'.upper()) +# 输出结果:HELLO WORLD 132 + +5. lower将字符串中的大写字母变成小写字母 +示例: +print('Hello World 132'.lower()) +# 输出结果:hello world 132 + +6. split字符串分割 +示例: +# 以空格方式进行分割,返回的是个列表 +print('Hello World 132'.split(' ')) +# 输出结果:['Hello', 'World', '132'] +# 使用join方法反向操作 +print(' '.join(['Hello', 'World', '132'])) +# 输出结果:Hello World 132 + +******元组和列表****** +列表和元组中可以保存多个数据,可以是任意类型的,每个元素之间用逗号隔开。 +元组tuple: 用小括号来表示 +tup = ('python', 66, 88.88, True, [11, 22, 33]) + +列表list: 用中括号来表示 +li = ['python', 66, 88.88, True, [11, 22, 33]] + +扩展: +序列类型的数据:数据内部的元素是由顺序的(有下标) +序列类型的数据:字符串,列表,元组 +序列类型数据的共同特性: +1. 可以通过下标取值:通过下标获取数据内的元素 +示例: +# 正向取值:从前往后数下标,下标从0开始 +print('python'[2]) # 输出结果:t +print(['python', 66, 88.88, True, [11, 22, 33]][1]) # 输出结果:66 +print(('python', 66, 88.88, True, [11, 22, 33])[0]) # 输出结果:python + +# 反向取值:从后往前数下标,下标从-1开始 +print('python'[-2]) # 输出结果:o +print(['python', 66, 88.88, True, [11, 22, 33]][-1]) # 输出结果:[11, 22, 33] +print(('python', 66, 88.88, True, [11, 22, 33])[-3]) # 输出结果:88.88 + +2. 可以通过切片操作:获取数据中某一段数据,[起始位置:终止位置], 左闭右开 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print('[起始位置:终止位置], 左闭右开:', li[0:3]) +# 输出结果:[起始位置:终止位置], 左闭右开: ['python', 66, 88.88] + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0211_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0211_notes.txt new file mode 100644 index 0000000..c884175 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0211_notes.txt @@ -0,0 +1,211 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******列表切片****** +可以通过切片操作:获取数据中某一段数据 +用法一: [起始位置:终止位置], 左闭右开 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print('[起始位置:终止位置], 左闭右开:', li[0:3]) +# 输出结果:[起始位置:终止位置], 左闭右开: ['python', 66, 88.88] + +# 使用反向的下标进行切片 +print(li[-2:-1]) # 输出结果:[True] + +# 正向和反向下标可以混用 +print(li[1:-2]) # 输出结果:[66, 88.88] + +用法二:[起始位置:终止位置:步长] +1. 步长为正数 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +# 默认步长为1,默认打印整个列表 +print(li[::]) # 输出结果: ['python', 66, 88.88, True, [11, 22, 33]] +# 步长为2, 2个元素中取第一个元素。所以是1 3 5 +print(li[::2]) # 输出结果: ['python', 88.88, [11, 22, 33]] +# 步长为3, 3个元素中取第一个元素。所以是1 4 +print(li[::3]) # 输出结果: ['python', True] +# 步长为4, 4个元素中取第一个元素。所以是1 5 +print(li[::4]) # 输出结果: ['python', [11, 22, 33]] + +2. 步长设置为负数 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +# 步长为-1, 是从后往前切片 +print(li[::-1]) # 输出结果:[[11, 22, 33], True, 88.88, 66, 'python'] +print(li[-1:-4:-1]) # 输出结果:[[11, 22, 33], True, 88.88] + +******列表的常见操作方法****** +列表list: 用中括号[]来表示 +列表可以保存多个数据,可以是任意类型的,每个元素之间用逗号隔开。 +列表可以转换成布尔值,空列表(li = [])的布尔值为False,其他的布尔值都是True。 + +1. 内置函数len:获取(字符串,列表,元组,字典,集合)的长度 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print(len(li)) # 输出结果:5 + +2. 新增列表元素 +append(): 在列表尾部追加元素 +示例: +li = ['nancy', 'lily'] +li.append('flora') +print(li) # 输出结果:['nancy', 'lily', 'flora'] + +insert(需要添加元素的下标位置, 需要添加的元素):指定位置添加元素 +示例: +li = ['nancy', 'lily', 'flora'] +li.insert(1, 'robot') +print(li) # 输出结果:['nancy', 'robot', 'lily', 'flora'] + +extend():一次性在列表尾部添加多个元素。注意:必须将需要添加的多个元素放在列表或者元组里面。 +示例: +li = ['nancy', 'lily', 'flora'] +li.extend(['jane', 'robot', 1, 2]) +print(li) # 输出结果:['nancy', 'lily', 'flora', 'jane', 'robot', 1, 2] + +3. 删除列表元素 +remove(元素值):删除列表指定的元素 +示例: +li = ['nancy', 'lily', 'flora'] +li.remove('lily') +print(li) # 输出结果:['nancy', 'flora'] + +pop():通过下标删除指定的元素,默认删除最后一个 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +li.pop() +print(li) # 输出结果:['nancy', 'lily', 'flora', 'robot'] +li.pop(1) +print(li) # 输出结果:['nancy', 'flora', 'robot'] + +clear():清空列表(删除列表中的所有元素) +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +li.clear() +print(li) # 输出结果:[] + +4. 查看列表元素 +通过下标取值 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +# 通过下标取值查找元素 +print(li[1]) # 输出结果:lily + +index():查找元素的下标值(找到第一个就返回,不会继续再查找;如果元素不存在会报错。) +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +index = li.index('flora') +print(index) # 输出结果:2 + +# 在指定范围内查找元素的下标值,左闭右开 +index = li.index('flora', 3, 6) +print(index) # 输出结果:5 + +count():查找列表中某个元素的个数 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +print(li.count('flora')) # 输出结果:2 + +5. 修改列表元素 +通过下标赋值 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +li[1] = 11 +print(li) # 输出结果:['nancy', 11, 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] + +6. 列表的其他方法 +sort():对列表进行排序(列表中全是数值类型);如果列表中全是字符串是按照ASCII值进行排序的。 +示例: +li = [11, 2, 353, 44, 88, 99, 123] +li.sort() # 默认从小到大排序, reverse默认为False +print(li) # 输出结果:[2, 11, 44, 88, 99, 123, 353] +li.sort(reverse=True) # 从大到小排序 +print(li) # 输出结果:[353, 123, 99, 88, 44, 11, 2] + +reverse():将列表反向,从末尾到起始排序 +示例: +li = [11, 2, 353, 44, 88, 99, 123] +li.reverse() # 此操作相当于 li[::-1] +print(li) # 输出结果:[123, 99, 88, 44, 353, 2, 11] + +copy():复制 +示例: +li = [1, 2, 3, 4, 5, 6, 7] +# 变量赋值,引用的是li中的数据 +li2 = li +print(id(li)) # 输出结果:2144668143360 +print(id(li2)) # 输出结果:2144668143360 +# 在列表类li2中追加元素,同样会作用到li中 +li2.append(9) +print(li) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] +print(li2) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] + +# 复制 +li3 = li.copy() +print(id(li3)) # 输出结果:2814574980480 +print(li is li3) # 输出结果:False +# 在列表类li3中追加元素,不会影响li +li3.append(80) +print(li) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] +print(li3) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9, 80] + +******运算符补充****** +身份运算符(is, is not):比较2个数据是否引用的是同一个对象(比较id内存地址是否一致) +示例: +li = [11, 2, 353, 44] +li2 = [11, 2, 353, 44] +li3 = li +# 内置函数id:查看数据的内存地址 +print(id(li)) # 输出结果:1792807521984 +print(id(li2)) # 输出结果:1792807540928 +print(id(li3)) # 输出结果:1792807521984 +print(li is li2) # 输出结果:False +print(li is li3) # 输出结果:True +print(li is not li3) # 输出结果:False + +扩展: +在python中 -5 到 256 之间的数据(小整数池),内存地址都是一样的。 +# 在终端运行 +a = -5 +b = -5 +print(id(a)) # 输出结果:140706950989280 +print(id(b)) # 输出结果:140706950989280 + +a = -6 +b = -6 +print(id(a)) # 输出结果:1739394026288 +print(id(b)) # 输出结果:1739394026352 + +成员运算符(in, not in):判断某个元素是否存在于列表中 +示例: +li = [1, 2, 3, 4, 5, 6, 7] +zs = 1 +ls = 8 +# 判断zs, ls是否存在于列表中 +print(zs in li) # 输出结果:True +print(ls in li) # 输出结果:False + +# 判断zs, ls是否不存在于列表中 +print(zs not in li) # 输出结果:False +print(ls not in li) # 输出结果:True + + +******元组****** +元组tuple: 用小括号来表示 +元组的方法只有查询的方法。没有添加元素,修改元素,删除元素的方法。 +1. 通过下标取值 +index():查找元素的下标值(找到第一个就返回,不会继续再查找;如果元素不存在会报错。) +示例: +tup = (1, 2, 33, 4, 5, 6, 33, 44, 33, 7) +print(tup[2]) # 输出结果:33 +print(tup.index(33)) # 输出结果:2 +print(tup.index(33, 3, 8)) # 输出结果:6 + +2. count():查找列表中某个元素的个数 +示例: +tup = (1, 2, 33, 4, 5, 6, 33, 44, 33, 7) +print(tup.count(33)) # 输出结果:3 diff --git a/python27Class/LearningNotesTXT/Python/flora_0213_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0213_notes.txt new file mode 100644 index 0000000..2a54f55 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0213_notes.txt @@ -0,0 +1,111 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******字典dict****** +1. 字典的定义 +花括号{}表示字典,字典中的元素是由键值(key:value)对组成的,每个元素用逗号隔开。 +字典是没有下标索引的,其键key就是索引。 +第一种:直接通过{'key': value}的形式定义 +dic = {'a': 11, 'b': 12} +第二种:使用dict()转换[('key', value), ('key', value) ...]这种数据类型 +dic = dict([('a', 11), ('b', 12)]) +第三种:dict(key = value, key = value ...) +dic = dict(a=11, b=12) + +示例: +dic = {} +dict2 = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(type(dic)) # 输出结果: +print(dict2) # 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dict2['name']) # 输出结果:flora + +2. 字典中的相关规范 +字典中的键不能重复。 +字典中的键只能使用不可变类型(字符串,数值类型,元组)的数据(通常是用字符串)。 +字典中的值可以是任何数据类型。 + +扩展: +不可变类型的数据:数值类型,字符串,元组 +可变类型的数据:列表,字典,集合 + +3. 字典的相关操作 +添加一个元素 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic['height'] = 156 +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200', 'height': 156} + +添加多个元素 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic.update({'height': 156, 'heavy': '56kg'}) +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200', 'height': 156, 'heavy': '56kg'} + +修改元素:键已存在就是修改。否则是新增。 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic['phone'] = '18956423668' +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '18956423668'} + +删除元素 +pop():通过键去删除指定的键值对,返回键对应的值 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.pop('phone') +print(res) # 输出结果:10220020200 +print(dic) +# 输出结果:{'name': 'flora', 'age': 18} + +popitem():删除最后添加进去的键值对,以元组的形式返回一个键值对 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.popitem() +print(res) # 输出结果:('phone', '10220020200') +print(dic) +# 输出结果:{'name': 'flora', 'age': 18} + + +查找元素 +通过键进行索引取值,键不存在会报错 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic['phone'] +print(res) # 输出结果:10220020200 + +get():通过键获取对应的值,键不存在不会报错,但是会返回None +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.get('phone') +print(res) # 输出结果:10220020200 +res2 = dic.get('heg') #键不存在 +print(res2) # 输出结果:None + +获取字典中的所有键,所有值,所有键值对 +keys():获取字典中所有的键 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.keys()) # 输出结果:dict_keys(['name', 'age', 'phone']) +print(list(dic.keys())) # 可通过list()转换成列表 +# 输出结果:['name', 'age', 'phone'] + +values():获取字典中所有的值 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.values()) # 输出结果:dict_values(['flora', 18, '10220020200']) +print(list(dic.values())) # 可通过list()转换成列表 +# 输出结果:['flora', 18, '10220020200'] + +items():获取字典中所有的键值对 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.items()) # 输出结果:dict_items([('name', 'flora'), ('age', 18), ('phone', '10220020200')]) +print(list(dic.items())) # 可通过list()转换成列表 +# 输出结果:[('name', 'flora'), ('age', 18), ('phone', '10220020200')] + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0215_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0215_notes.txt new file mode 100644 index 0000000..b038d49 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0215_notes.txt @@ -0,0 +1,231 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******集合****** +1. 集合的定义 +集合: set类型, 通过{}来表示 +内部的数据{value, value1, value2} +示例: +set1 = {11, 22, 33, 44, 55} +print(type(set1)) # 输出结果: + +2. 集合的特性 +集合的数据不能存在重复的元素; +集合中的数据只能是不可变类型(数值类型,字符串,元组); +集合和字典都是无序的,没有下标索引; +集合是可变类型的数据。 +集合的操作: + add: 添加数据 + pop:删除数据 +示例: +set1 = {11, 22, 33, 44, 55, 55} +print(set1) # 输出结果:{33, 11, 44, 22, 55} +set1.add(678) +print(set1) # 输出结果:{33, 678, 11, 44, 22, 55} +set1.pop() # 随机删除一个元素 +print(set1) # 输出结果:{678, 11, 44, 22, 55} + +3. 集合的应用 +对数据的去重 +示例: +# 对字符串去重 +str1 = 'dfgdfghjkhjk' +s1 =set(str1) +print(s1) # 输出结果:{'d', 'k', 'f', 'j', 'g', 'h'} +# 对列表去重 +li = [11, 11, 22, 22, 33] +s1 =set(li) +print(list(s1)) # 输出结果:[33, 11, 22] + +用来区分数据是否可变 +# 运行不报错的就都是不可变类型的:数值类型,字符串,元组 +set1 = {111, 12.33, '243', True, (1, 2)} + +# 运行报错的就都是可变类型的:列表,字典,集合 +# set2 = {[1, 2, 3]} # TypeError: unhashable type: 'list' +# set3 = {{'name': 'flora'}} # TypeError: unhashable type: 'dict' +set4 = {{1,2,3}} # TypeError: unhashable type: 'set' + + +******数据类型总结****** +1. 按数据结构分类 +数值类型:整数,浮点数,布尔值 +序列类型:字符串,列表,元组(可以通过下标取值,支持切片操作) +散列类型:字典,集合(元素内部是无序的,没有下标) + +2. 数据类型的可变与不可变 +不可变类型:数值类型,字符串,元组 + 字符串和元组定义之后不能修改内部结构或者值(内存单元中的值),为不可变类型 +可变类型:列表,字典,集合 +如何区分可变不可变数据:定义一个集合,把数据放到集合中看会不会报错。会报错的是可变类型。 + +******控制流****** +顺序:代码从上往下执行 +分支:根据不同的条件,执行不同的代码 +循环:特定的代码重复执行 +注意:python中通过缩进来区分代码块的。 + +******条件判断****** +1. if语句 +if 条件: + # 条件成立执行的代码块 + +示例: +# 用户输入考试成绩,请判断是否及格。 +score = float(input('请输入您的成绩:')) +if score >= 60: + # 条件成立执行的代码块 + print('考试及格!') + + +2. if - else语句 +if 条件: + # 条件成立执行的代码块 +else: + # 条件不成立执行的代码块 + +示例: +# 用户输入考试成绩,请判断是否及格。如果考试不及格,打印:考试不及格,晚上通宵敲代码! +score = float(input('请输入您的成绩:')) +if score >= 60: + # 条件成立执行的代码块 + print('考试及格!') +else: + # 条件不成立执行的代码块 + print('考试不及格,晚上通宵敲代码!') + +3. if - elif - else语句 +if 条件1: + # 条件成立执行的代码块 +elif 条件2: + # 条件2成立执行的代码块 +elif 条件3: + # 条件3成立执行的代码块 +else: + # 以上条件均不成立执行的代码块 + +# 用户输入考试成绩,根据不同等级进行区分(A: 90分以上, B:80-90分, C: 60-80分, D:60分以下) +score = int(input('请输入您的成绩:')) +if 0 <= score < 60: + print('您的成绩为D!') +elif 60 <= score < 80: + print('您的成绩为C!') +elif 80 <= score < 90: + print('您的成绩为B!') +elif 90 <= score < 100: + print('您的成绩为A!') +else: + print('您输入的成绩有误!') + + +4. 多个条件同时判断 +# 登录小案例:事先存储一组账号密码,提示用户输入账号和密码,然后判断账号密码是否输入正确 +user_info = {'user': 'flora', 'pwd': '123455555Az'} + +username = input('请输入账号:') +passwd = input('请输入密码:') + +# 方式一:使用嵌套方式 +if username == user_info['user']: + if passwd == user_info['pwd']: + print('账号密码输入正确!') + else: + print('密码输入不正确!') +else: + print('账号输入不正确!') + +# 方式二:使用逻辑运算符去判断多个条件 +if username == user_info['user'] and passwd == user_info['pwd']: + print('账号密码输入正确!登录成功!') +else: + print('账号或密码输入不正确!登录失败!') + +总结: +使用if开启一个条件判断语句: + 一个条件语句中只有一个if,但是一个条件语句中可以有多个或者一个或者零个elif; + 一个条件语句中只有一个或者零个else。 +if判断成立的标准: + if成立的标准是根据if后面的python表达式或者数据的布尔值是否为True来确定条件是否成立 + +******python中数据的布尔值****** +非0位True:None, 数字0或者数据长度为0(len())的布尔值为False, 其他数据布尔值都是True; +数据长度为0, 例如:空字符串,空列表,空元祖,空字典 + +示例: +str1 = 'python' +li = [1, 2, 2] +if li: + print('成立!') +else: + print('不成立!') + +******while循环(条件循环)****** +1. while循环的使用 +如果条件一直成立,则一直循环做条件满足的事情,直到条件不成立,结束循环。 +while 条件: + # 条件成立,循环执行的代码块 + # 条件成立,循环执行的代码块 + # 条件成立,循环执行的代码块 + # ...... + +示例: +# 创建一个变量来保存循环的次数 +i = 0 +while i < 5: + print('hello python') + i += 1 # i = i + 1 +# 输出结果: +""" +hello python +hello python +hello python +hello python +hello python +""" +2. 死循环以及相关案例的使用 +死循环:循环的条件一直成立,在循环体中无限循环,称之为死循环。 +避免写代码的过程中因为逻辑问题,造成代码死循环。 +示例: +while True: + print('hello python') + +3. break强制跳出循环 +死循环在特定的需求下,我们也会使用,再循环内部要实现跳出循环的机制(合理使用break)。 +示例: +while True: + user_info = {'user': 'flora', 'pwd': '123455555Az'} + username = input('请输入账号:') + passwd = input('请输入密码:') + + if username == user_info['user'] and passwd == user_info['pwd']: + print('账号密码输入正确!登录成功!') + break + else: + print('账号或密码输入不正确!请重新输入!') + +4. 循环内嵌套条件语句 +示例: +# 打印3次之后强制退出循环 +i = 0 +while i < 5: + print('hello python') + i += 1 # i = i + 1 + # 当i=3时,退出循环 + if i == 3: + break + +5. continue终止本轮循环,直接进行下次循环的条件判断 +示例: +# 第5-7次不打印 +i = 0 +while i < 10: + i += 1 # i = i + 1 + # 当i在5~7之间,则执行continue终止本轮循环,进行下轮循环的条件判断 + if 5 <= i <= 7: + continue + print('hello python') + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0218_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0218_notes.txt new file mode 100644 index 0000000..a27403a --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0218_notes.txt @@ -0,0 +1,169 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******for循环****** +1. 定义 +for i in xxx: + # 循环体 + +2. 遍历字符串 +示例: +str1 = 'flora' +for i in str1: + print(i) + +3. 遍历列表 +示例: +# 当前有10位同学的成绩,在一个列表中,请区分成绩的等级 +li = [90, 78, 56, 89, 65, 80, 74, 34, 89, 100] +for score in li: + if 0 < score < 60: + print('成绩{}:不及格'.format(score)) + elif 60 <= score < 80: + print('成绩{}:及格'.format(score)) + elif 80 <= score < 90: + print('成绩{}:优秀'.format(score)) + else: + print('成绩{}:非常优秀'.format(score)) + +4. 遍历字典 +示例: +dic1 = {'name': 'flora', 'gender': 'girl', 'age': 18} +for i in dic1.keys(): + print('遍历字典的键:', i) + +for i in dic1.values(): + print('遍历字典的值:', i) + +for i in dic1.items(): + print('遍历字典的键值对:', i) + +# 遍历字典键值对时,用2个变量分别保存键和值。 +# for i in dic1.items(): +# k, v = i +# print('遍历字典的键:', k) +# print('遍历字典的值:', v) + +for k, v in dic1.items(): + print('遍历字典的键:', k) + print('遍历字典的值:', v) + +5. for循环中的break, continue +示例: +# 需求一:打印10遍hello python +for i in range(1, 11): + print('1: 这是第{}遍: hello python'.format(i)) + +# 需求二:打印到第50遍跳出循环 +for i in range(1, 11): + print('2: 这是第{}遍: hello python'.format(i)) + if i == 5: + break + +# 需求三:第3~5遍不打印 +for i in range(1, 11): + if 3 <= i <= 5: + continue + print('3:这是第{}遍: hello python'.format(i)) + +6. for循环中的高级语法:for -- else +for对应的else语句,只有当循环是通过break结束的时候,不会执行。其他情况下都会执行。 +示例: +for i in range(10): + print('本轮遍历的数据为{}'.format(i)) +else: + print('for对应的else语句') + +示例: +users = [{'user': 123}, {'user': 122}, {'user': 124}] +user = input('请输入您的账号:') +for i in users: + if user == str(i['user']): + print('用户已存在!') + break + else: + print('用户不存在!') +# 缺陷:输入1111,会打印3遍:用户不存在 + +for i in users: + if user == str(i['user']): + print('用户已存在!') + break +else: + print('用户不存在!') + + + +******内置函数range()****** +range(n): 默认生成0 ~ n-1的整数序列。对于这个序列,我们可以通过list()转化为列表类型的数据。 +range(n, m):左闭右开,默认生成从n ~ m-1的整数序列。 对于这个序列,我们可以通过list()转化为列表类型的数据。 +range(n, m , k):左闭右开,n初始值,m-1结束值, k步长, 递增或者递减的整数序列。 + 默认生成从n ~ m-1,并且间隔k的整数序列。 对于这个序列,我们可以通过list()转化为列表类型的数据。 + +# 示例: +print(list(range(10))) # 输出结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +print(list(range(1, 10))) # 输出结果: [1, 2, 3, 4, 5, 6, 7, 8, 9] +print(list(range(2, 8, 2))) # 输出结果: [2, 4, 6] + +print(list(range(101, 5, -5))) +# 输出结果: [101, 96, 91, 86, 81, 76, 71, 66, 61, 56, 51, 46, 41, 36, 31, 26, 21, 16, 11, 6] + +print(list(range(5, 101, 5))) +# 输出结果: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] + + + +******元组拆包***** +示例: +tu = (111, 222) +a, b = tu +print(a, b) # 输出结果:111 222 + + +******函数***** +1. 常用的内置函数 +type():查看数据的类型 +id(): 查看数据的内存地址 +len():查看数据的长度 +range(): 生成数据 + +2. 函数的定义 +def 函数名(): + # 函数内部的功能代码 + # 函数内部的功能代码 + # 函数内部的功能代码 + +可以将单一的功能封装成一个函数,在需要使用该功能的时候直接调用函数就可以了。 +函数的作用: 封装代码。 +函数的意义:提高代码的重用率。 +函数的命名规范:可以由数字下划线组成,不能使用数字开头;不能使用python关键字,不要和内置函数和模块(第三方模块,官方库)重名。 +函数的命名风格:推荐使用下划线命名法。 + +示例: +def func(n): + for i in range(n): + for j in range(i + 1): + print('* ', end='') + print() +func(5) + +3. 函数的参数:定义在函数后面的括号中 +定义的参数叫形参,调用函数的时候传入的参数叫实参。 +示例: +def add_number(a, b): + print('a+b: ', a + b) +add_number(3, 5) + +4. 函数的返回值:return +# 注意:如果接收到的数据为None, 说明没有返回值 +示例: +def add_number(a, b): + return a + b +res = add_number(3, 5) +print(res) + + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0220_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0220_notes.txt new file mode 100644 index 0000000..606ac1b --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0220_notes.txt @@ -0,0 +1,145 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******函数的返回值***** +函数中的返回值是由return来决定的。 +函数中没有return就没有返回值,调用函数得到的结果就是None。 +函数中返回多个值,直接下载return后面用逗号隔开就可以。 +当函数执行到return之后,就会直接跳出函数,返回结果,后面的代码都不会再执行了。 + +******函数的参数***** +1. 实参分类(实参可以是变量): + 位置传参/位置参数:通过位置按顺序传递 + 关键字传参/关键字参数:通过参数名指定参数进行传递 +示例: +def add_number(a, b): + print('a+b: ', a + b) + return a + b +# 位置传参 +res = add_number(3, 5) +# 关键字传参 +res1 = add_number(b=9, a=10) +print(res, res1) + +注意点: + 位置参数与关键字参数可以一起用。 + 但是同时使用时,位置参数写前面,关键字参数写后面。 +示例: +def add_number(a, b, c): + return a + b + c +# 位置传参 + 关键字传参 +res = add_number(3, c=5, b=4) +print(res) + +2. 形参:函数括号里面的就是形参 +形参的分类: + 必备参数(必须参数):定义了几个参数就要传递几个参数。 + 默认参数(缺省参数):可传可不传,不传的情况下使用默认值,传了的情况下使用传的值。 + 不定长参数:位置可前可后,但是一般放在后面。 + *args:接收0个或多个位置参数 + **kwargs:接收0个或多个关键字参数 + +示例: +# 必备参数 +def add_number(a, b, c): + return a + b + c +res = add_number(3, 7, 8) +print(res) + +# 默认参数: 可传可不传 +def add_number1(a, b, c=90): + return a + b + c +res1 = add_number1(3, 7, 8) +res2 = add_number1(3, 87) +print(res1, res2) + +# 不定长参数 +def add_number2(a, b, c, *args): + print('a=', a) + print('b=', b) + print('c=', c) + print(args) +add_number2(3, 7, 8, 45, 55, 6, 66) + +def add_number2(a, b, c, **kwargs): + print('a=', a) + print('b=', b) + print('c=', c) + print(kwargs) +add_number2(a=3, b=7, c=8, d=45, e=55, f=6, g=66) + + +******函数参数的拆包***** +函数定义: + *:表示接收位置参数的不定长参数 + **:表示接收关键字参数的不定长参数 +示例: +def func(*args, **kwargs): + print(args) + print(kwargs) +func(11,22,33, c = 7, d = 9, e = 10) +# 输出结果:(11, 22, 33) +# {'c': 7, 'd': 9, 'e': 10} + +函数调用: + *:可以对元组或列表拆包 + **:可以对字典拆包 +示例: +def func(a, b, c, d): + print(a) + print(b) + print(c) + print(d) +tu= (11, 22, 33, 44) +li = [333, 555, 777, 888] +dic = {'a': 1, 'b': 2, 'c': 3, 'd': 4} +# 对元组,列表进行拆包 +func(*tu) +func(*li) +# 对字典进行拆包 +func(**dic) + +******函数的作用域***** +1. 全局变量&局部变量 +全局变量:直接定义在文件/模块中的变量。在该文件的任何地方都可以访问。 +局部变量:定义在函数内部的变量。只有在函数内部才可以访问。 +示例: +# 全局变量 +a = 100 +def func(): + # 局部变量 + b = 10 + print('打印全局变量a=', a) + print('打印局部变量b=', b) +print('打印全局变量a=', a) + +2. 作用域 +局部变量的作用域:函数内部 +函数参数的作用域:函数内部 + +3. 在函数内部定义全局变量:使用global进行声明 +示例: +def func(a, b): + # 全局变量 + global c + c = 10 + print('a=', a) + print('b=', b) + print('c=', c) +func(1, 3) +print(c) + +4. 函数内部变量和全局变量同名时,在函数内部访问该变量,会优先使用局部变量 +示例: +a = 100 +def func(): + a = 10 + print('a=', a) +func() # 输出结果: a= 10 + + + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0222_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0222_notes.txt new file mode 100644 index 0000000..2704e28 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0222_notes.txt @@ -0,0 +1,221 @@ + +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******内置函数***** +1. min()获取最小值;只能对一组数据进行操作,不能对字符串进行操作。 +示例: +tu = (11, 22, 33) +print('获取元组中的最小值:', min(tu)) +li = [345, 789, 890] +print('获取列表中的最小值:', min(li)) +dic = {'a': 1, 'b': 9} +print(min(dic.values())) + +2. max()获取最大值;只能对一组数据进行操作,不能对字符串进行操作。 +示例: +tu = (11, 22, 33) +print('获取元组中的最大值:', max(tu)) +li = [345, 789, 890] +print('获取列表中的最大值:', max(li)) +dic = {'a': 1, 'b': 9} +print(max(dic.values())) + +3. sum()求和;只能对一组数据进行操作,不能对字符串进行操作。 +示例: +tu = (11, 22, 33) +print('获取元组中元素之和:', sum(tu)) +li = [345, 789, 890] +print('获取列表中元素之和:', sum(li)) +dic = {'a': 1, 'b': 9} +print(sum(dic.values())) + +4. enumerate()获取数据的索引和值 +示例: +dic = {'a': 1, 'b': 9} +li = [345, 789, 890] +tu = (11, 22, 33) +print(list(enumerate(tu))) +# 输出结果:[(0, 11), (1, 22), (2, 33)] + +print(list(enumerate(li))) +# 输出结果:[(0, 345), (1, 789), (2, 890)] + +print(list(enumerate(dic))) +# 输出结果:[(0, 'a'), (1, 'b')] + +5. filter(参数1, 参数2) +参数1:函数(过滤的规则) +参数2:需要过滤的数据 +filter会根据参数-函数的返回值是True还是False来决定数据要不要过滤 +示例: +li = [11, 22, 34, 6, 345, 789, 890] +def fun(x): + return x > 50 +res = filter(fun, li) +print(list(res)) + +6. 匿名函数:lambda 函数参数: 返回值 +应用场景:一般用于非常简单的函数(函数内部只有一行代码) + 比如:结合过滤器filter()使用(当成别的函数的参数) +示例: +li = [11, 22, 34, 6, 345, 789, 890] +res = filter(lambda x: x>50, li) +print(list(res)) + +li1 = [11, 22, 34, 6, 345, 789, 890] +li2 = [11, 22, 33, 44, 565, 890, 789, 5, 6, 7, 8] +print(list(filter(lambda x: x in li1, li2))) + +print(list(filter(lambda x: x % 5 == 0, range(101)))) + +7. eval():能够识别字符串中的有效python表达式 +示例: +str1 = "{'a': 1, 'b': 2, 'c': 3}" +print(type(str1)) +# 输出结果: +print(type(eval(str1))) +# 输出结果: + +str2 = "[11, 22, 33, 44]" +print(type(eval(str2))) +# 输出结果: + +# 如果eval需要识别的字符串里面是个变量名,会打印出变量对应的值 +b = 111 +str3 = 'b' +print(eval(str3)) +# 输出结果:111 + +# 注意点:只能去掉一层引号 +str4 = "'bcd'" +print(eval(str4)) +# 输出结果:bcd + +8. zip()聚合打包 +注意:zip对象只能进行一次强制转换 +示例: +li1 = ['name', 'age', 'gender'] +li2 = ['flora', 18, 'female'] +res = zip(li1, li2) +print(dict(res)) +# 输出结果:{'name': 'flora', 'age': 18, 'gender': 'female'} +res1 = zip(li1, li2) +print(list(res1)) +# 输出结果:[('name', 'flora'), ('age', 18), ('gender', 'female')] + +# 按照顺序一一对应,长度不一致的情况下,只取最短的 +li3 = ['name', 'age', 'gender', 'info'] +li4 = ['flora', 18, 'female'] +res2 = zip(li3, li4) +print(dict(res2)) +# 输出结果:{'name': 'flora', 'age': 18, 'gender': 'female'} +res3 = zip(li3, li4) +print(list(res3)) +# 输出结果:[('name', 'flora'), ('age', 18), ('gender', 'female')] + +# zip扩展使用 +示例: +li1 = [11, 22, 33, 44] +li2 = [1, 2, 3, 4, 5] +li3 = [111, 222, 333, 444, 555] +li4 = [11, 12, 13, 14, 15] + +res1 = zip(li1, li2, li3, li4) +print(tuple(res1)) # 输出结果:[(11, 1, 111, 11), (22, 2, 222, 12), (33, 3, 333, 13), (44, 4, 444, 14)] + +res2 = zip(li1, li2, li3, li4) +print(list(res2)) # 输出结果:((11, 1, 111, 11), (22, 2, 222, 12), (33, 3, 333, 13), (44, 4, 444, 14)) + +res3 = zip(li1, li2, li3, li4) +print(dict(res3)) # 报错:ValueError: dictionary update sequence element #0 has length 4; 2 is required + +******文件的操作***** +1. 打开文件 +open(参数1, 参数2, encoding='utf8') +参数1:文件名/文件路径 +参数2:文件打开的模式 +文件打开的模式: + r:读取文件;文件不存在会报错。 + a:追加写入, 在文件后面写入新的内容,原有内容不变;文件不存在会新建一个。 + w:覆盖写入, 覆盖原有文件内容,写入新的内容;文件不存在会新建一个。 + + # 以下三种模式是以二进制的模式打开文件(常用于图片视频等文件的操作) + rb:读取文件;文件不存在会报错。 + ab:追加写入, 在文件后面写入新的内容,原有内容不变;文件不存在会新建一个。 + wb:覆盖写入, 覆盖原有文件内容,写入新的内容;文件不存在会新建一个。 + +文件读写操作的模式(扩展): + r+:读取文件并写入内容;文件不存在会报错。 + a+:读取文件并追加写入, 在文件后面写入新的内容,原有内容不变;文件不存在会新建一个。 + w+:读取文件并覆盖写入, 覆盖原有文件内容,写入新的内容;文件不存在会新建一个。 + + # 以下三种模式是以二进制的模式打开文件并写入内容(常用于图片视频等文件的操作) + rb+:读取文件并写入内容;文件不存在会报错。 + ab+:读取文件并追加写入, 在文件后面写入新的内容,原有内容不变;文件不存在会新建一个。 + wb+:读取文件并覆盖写入, 覆盖原有文件内容,写入新的内容;文件不存在会新建一个。 + +2. 读取文件 +文件读取的方法: + read()读取文件中所有的内容 + readline()读取一行内容 + readlines()按行读取所有内容,返回一个列表 + +3. 关闭文件 +关闭文件: + close() + +4. 文件写入 +文件写入的方法: + write() + +# -------------- 基本读取操作 --------------------- +示例: +# 打开文件 encoding='utf8'是可选参数 +# f = open(file='flora_0213_notes.txt', mode='r', encoding='utf8') +f = open('flora_0213_notes.txt', 'r', encoding='utf8') +# 读取文件 +content = f.read() +# 打印文件内容 +print(content) +# 关闭文件 +f.close() + +# -------------- 指定路径读取 ---------------------- +示例: +f = open(r'E:\PycharmProject\ChyClass\UITest\Test.py', 'r', encoding='utf8') +print(f.readlines()) +f.close() + +# -------------- 写入文件 ---------------------- +示例: +f = open('test4.txt', 'w', encoding='utf8') +f.write('4444' + '\n') +f.close() + +# -------------- 读取写入图片---------------------- +示例: +# 读取图片 +f = open('picture.jpg', 'rb') +content = f.read() +print(content) +# 写入图片 +f2=open('picture.jpg', 'wb') +f2.write(content) +f.close() +f2.close() + +5. 文件上下文管理器对象 +with 语句 +语法格式: + with open(文件名,打开模式) as 接收文件句柄的变量: + # 文件的读写操作 + +使用with操作文件的优点:不用自己关闭文件,文件会自动关闭。 + +示例: +with open('test.txt', 'r', encoding='utf8') as f: + print(f.read()) \ No newline at end of file diff --git a/python27Class/LearningNotesTXT/Python/flora_0225_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0225_notes.txt new file mode 100644 index 0000000..19b7add --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0225_notes.txt @@ -0,0 +1,165 @@ + +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******模块的导入***** +模块就是python文件,一个py文件称之为一个模块。 + +import 模块名 (同级目录) +from 包名(文件夹) import 模块名 + +# 多层级下的模块导入-从项目路径下一级级的导入 +from 包名.包名.包名(...) import 模块名 + +示例: +目录结构如下: +python27Class/LearningNotesTXT/test1.py +python27Class/test.py +python27Class/FloraHomeWork_0225.py + +在FloraHomeWork_0225.py中要用到test.py以及test1.py中的变量和函数 + +# 第一种导入方式: +import test +# 第二种导入方式: +from python27Class import test +from python27Class.LearningNotesTXT import test1 + +******标识符***** +python中自己起的名字都叫标识符(变量名,函数名,模块名,包名,类名)。 +标识符:只能由数字字母下划线组成,不能使用数字开头。 + +******python中的包***** +新建python的包,包下面会默认带有__init__.py文件 +from 包名 import __init__.py中的变量 + +示例: +目录结构如下: +python27Class/Pack/__init__.py/变量aaa +python27Class/FloraHomeWork_0225.py + +在FloraHomeWork_0225.py中导入 +from python27Class.Pack import aaa +print(aaa) + +******导入模块中的某个变量(函数、类)***** +from 模块名 import 变量名 +from 包名(文件夹).模块 import 变量名/函数名(多个用逗号隔开) + +示例: +目录结构如下: +python27Class/Pack/test3.py +python27Class/FloraHomeWork_0225.py + +在FloraHomeWork_0225.py中导入 +# 导入变量 +from python27Class.Pack.test3 import test3 +# 导入函数 +from python27Class.Pack.test3 import func_03 +# 调用变量以及函数 +print(test3) +func_03() + +******导入的时候起别名***** +from 模块名 import 变量名 as 别名(自定义的名称) + +示例: +from random import randint as rt +print(rt(1, 100)) + +******python内置的魔法变量__name__****** +注意:在进行模块导入的时候,会将被导入的模块执行一遍 +__name__的值不是固定的; +直接运行该文件:__name__值是__main__ +在进行模块导入的时候, __name__的值是导入的模块名/包名(文件夹).模块名 + +示例: +python27Class/Pack/test3.py/print('test3.py中的__name__:', __name__) +python27Class/FloraHomeWork_0225.py + +在FloraHomeWork_0225.py中导入 +from python27Class.Pack import test3 # 打印:test3.py中的__name__: python27Class.Pack.test3 + +如果不希望当前模块中的某些代码在被导入的时候被执行,可以用如下方式解决: +# 这个条件只有在直接运行的时候才会成立。 +# 通过模块导入的方式,该条件不会成立。 +if __name__ == '__main__': + print('被其他模块导入的时候,这部分代码不会执行') + +******查看模块导入的搜索路径****** +import sys +for i in sys.path: + print(i) + +******路径处理****** +# 相对路径表示法: + . 表示当前目录 + .. 表示父级目录 + +示例: +import os +# 获取绝对路径 .表示当前文件 +res = os.path.abspath('.') +print(res) + +# 获取当前文件的父级目录的绝对路径 +print(os.path.abspath('..')) + +# 获取当前文件的父级目录的绝对路径 +res = os.path.abspath(__file__) +print(os.path.dirname(res)) + +# 获取项目路径,通过是通过这样的方法 +Basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +******路径拼接****** +os.path.join() +示例: +import os +Basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +print(os.path.join(Basedir, 'ChyClass')) + +******魔法变量__file__****** +__file__表示当前文件的文件名 +注意:pycharm下面做了优化处理,打印的是一个文件路径 + +示例: +# 打印的结果是一样的,但是出来路径是斜杠/ +print(__file__) # 输出结果:E:/PycharmProject/ChyClass/python27Class/FloraHomeWork_0225.py +# 打印的结果是一样的,但是打印出来路径是反斜杠\ +print(os.path.abspath(__file__)) # 输出结果:E:\PycharmProject\ChyClass\python27Class\FloraHomeWork_0225.py + +******OS模块中的扩展方法****** +Linux命令 os模块中的方法 +pwd os.getcwd() 获取当前的工作路径 +cd os.chdir() 切换路径 +ls os.listdir() 获取当前工作路径下的文件和文件夹信息 +mkdir os.mkdir() 当前工作路径下创建文件夹 +rmdir os.rmdir() 当前工作路径下删除文件夹 + os.path.isfile 判断给定的路径是否文件路径 + os.path.isdir 判断给定的路径是否是文件夹路径 + +示例: +import os +# 获取当前的工作路径 +print(os.getcwd()) + +# 切换路径到C盘 +os.chdir('C:') +print(os.getcwd()) + +# 获取当前工作路径下的文件和文件夹信息 +print(os.listdir('..')) + +# 当前工作路径下创建文件夹 +os.mkdir('ccca') # 如果已存在,无法创建,会报错 + +# 判断给定的路径是否文件路径 +print(os.path.isfile('E:\PycharmProject\ChyClass\python27Class')) + +# 判断给定的路径是否是文件夹路径 +print(os.path.isdir('E:\PycharmProject\ChyClass\python27Class')) \ No newline at end of file diff --git a/python27Class/LearningNotesTXT/Python/flora_0227_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0227_notes.txt new file mode 100644 index 0000000..cb73df9 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0227_notes.txt @@ -0,0 +1,126 @@ +================================= + HomeWork +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******异常****** + +1. 对于有可能会出错的代码, 我们可以对这行代码进行异常捕获。 +try-except +try-except-else +try-except-else-finally +try-except-finally + +示例: +try: + a = int(input('请输入一个数字:')) +except: + print('出错啦!(try里面的代码出现了异常执行except中的代码)') +else: + print('try里面的代码没有出现异常的时候执行else中的代码') +finally: + print('不管代码是否出现异常,都会执行!') + +2. 捕获指定类型的异常 +示例: +try: + a = int(input('请输入一个数字:')) + print(b) +except NameError: # 指定异常才会被捕获。出现其他异常还是会报错。 + print('出错啦!(出现NameError会打印)') + +3. 可以定义变量来接收异常 +示例: +try: + a = int(input('请输入一个数字:')) + print(b) +except NameError as e: + print('当前出错的原因:', e) # 输出结果:name 'b' is not defined + print('出错啦!(出现NameError会打印)') + +4. 捕获多个异常 +示例: +# 方法一:使用多个except(不同的异常类型,可以做不同的处理) +try: + a = int(input('请输入一个数字:')) + print(b) +except NameError as e: + print('当前出错的原因:', e) + print('出错啦!(出现NameError会打印)') +except ValueError as e2: + print('当前出错的原因:', e2) + print('出错啦!(出现ValueError会打印)') + + +# 方式二:一个except(不同异常做相同处理) +try: + a = int(input('请输入一个数字:')) + print(b) +except (NameError, ValueError) as e: + print('当前出错的原因:', e) + print('出错啦!(出现NameError, ValueError会打印)') + +# 注意:上述代码中,try的第一行代码出现异常,try中的第二行代码就不会执行了 + +5. 捕获不确定的异常, 可以直接捕获常见异常类型的父类 +示例: +try: + import requests + requests.ger(url='www.baidu.com') +except Exception as e: + print('出错的原因:', e) + +6. else场景应用 +示例: +import os +# 复制指定路径下的文件到当前文件所在的目录 +def file_copy(path): + try: + file_list = os.listdir(path) + except FileNotFoundError as e: + print('你传入的路径不对,出现了错误,错误提示{}'.format(e)) + # 获取文件路径没有出错才执行以下代码 + else: + for file in file_list: + # 定位目标目录的文件 + file_path = os.path.join(path, file) + + # 如果是文件,则进行文件复制 + if os.path.isfile(file_path): + # 读取文件的内容 + with open(file_path, 'rb') as f: + content = f.read() + + # 将上面读取到的内容写入到新文件中, 新文件跟当前文件同级,并且命名带有cp + # with open(os.path.join(os.getcwd(), 'cp' + file), 'wb') as f: + with open('cp' + file, 'wb') as f: + f.write(content) + +file_copy('path') + +7. finally应用场景 +示例: +# 通过finally来关闭文件 +f = open('case.txt', 'w', encoding='utf-8') +try: + n= input('请输入数字:') +except: + f.write('代码错误了!') +else: + f.write('代码没有错误了!') +finally: + print('finally执行了!') + f.close() + +8. raise:主动抛出异常 +示例: +print('-----------------------') +# raise ValueError('这个自定的错误提示') +raise AssertionError +print('-----------------------') + +9. assert断言 +excepted = '用例执行通过' +result = '用例执行未通过' +assert excepted == result # 不相等,会抛出异常AssertionError diff --git a/python27Class/LearningNotesTXT/Python/flora_0229_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0229_notes.txt new file mode 100644 index 0000000..0ad6535 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0229_notes.txt @@ -0,0 +1,243 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******面向对象****** +******类class****** +1. 类的定义 +关键字:class +语法: +class 类名: + # 类里面的代码 + +类名命名规范:遵循标识符的命名规范,风格采用大驼峰命名法,例如CatType + +示例: +class Cat: + pass + +class Dog: + pass + +class TestCase: + pass + +2. 通过类创建对象 +对象 = 类名() +关于对象,有人叫对象,也有人叫实例。 +通过类来创建对象(实例化对象)。可以创建多个对象,每个对象的内存地址都不一样。 +示例: +class Cat: + pass + +# 通过类来创建对象(实例化对象)。可以创建多个对象,每个对象的内存地址都不一样。 +kitty = Cat() +print(id(kitty)) # 输出结果:2108715911296 + +coffee = Cat() +print(id(coffee)) # 输出结果:2108716016880 + +******类属性和实例属性****** +1. 类属性 +这一类事物拥有的共同特征,我们通常会定义为类属性。 +在类里面直接定义的变量,叫做类属性。 +类属性:可以通过类和对象去访问 + +有两种方式可以访问类属性: + 通过对象访问类属性:对象名.属性名。 + 通过类访问属性:类名.属性名。 + +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + +# 通过对象访问类属性:对象名.属性名 +kitty = Cat() +print(kitty.leg) # 输出结果:四条腿 + +coffee = Cat() +print(coffee.tail) # 输出结果:长尾巴 + +# 通过类访问属性:类名.属性名 +print(Cat.leg) # 输出结果:四条腿 + +2. 实例属性 +每个对象的属性值都有可能不一样,就应该定义为实例属性(对象属性)。 +实例属性的定义:对象.属性名=属性值。 +对象属性(实例属性):只能对象自己能用。 +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + +# 实例化对象 +kitty = Cat() +coffee = Cat() + +# 给对象添加属性 +kitty.name = 'kitty' +kitty.age = 2 + +coffee.name = 'coffee' +coffee.age = 3 + +# 通过对象访问对象属性:对象名.属性名 +print(kitty.name) # 输出结果:kitty +print(kitty.age) # 输出结果:2 + +print(coffee.name) # 输出结果:kitty +print(coffee.age) # 输出结果:3 + +3. 关于如何在类里面定义对象属性 +定义在类里面的函数叫方法。 +__init__方法: + 初始化方法; + 在创建对象的时候,会自动调用执行里面的代码。 +关于方法中的第一个参数self:self代表对象,不用手动传参,调用该方法时会自动传入。 +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + def __init__(self): + # 初始化方法 + print('这里是打印self', id(self), self) + print('这个是__init__方法在调用') + +kitty = Cat() # 输出结果:这里是打印self 1396410304640 <__main__.Cat object at 0x00000145208A4880> +print('这里是打印kitty', id(kitty), kitty) +# 输出结果:这里是打印self 1396410304640 <__main__.Cat object at 0x00000145208A4880> + +print('----------------------') + +coffee = Cat() # 输出结果:这里是打印self 2197480466656 <__main__.Cat object at 0x000001FFA40AE8E0> +print('这里是打印coffee', id(coffee), coffee) +# 输出结果:这里是打印coffee 1796880263392 <__main__.Cat object at 0x000001A25E68E8E0> + +__init__方法的作用:初始化对象属性 +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + def __init__(self, name, age, gender): + self.name = name + self.age = age + self.gender = gender + +kitty = Cat('hello kitty', 1, 'female') +print(kitty.name) + +coffee = Cat('coffee cat', 2, 'male') +print(kitty.age) + +4. 类里面的方法 +特征 + 行为 +特征:属性(类属性和实例属性) +行为:方法(类方法和实例方法) +方法的本质就是类里面的函数。 + + +实例方法: + 第一个参数时self, self代表的是对象本身,哪个对象调用该方法,self就代表哪个对象。 + 实例方法只能通过对象去调用。 + 实例方法不能通过类去调用,调用会报错。 + +类方法: + @classmethod进行装饰(标识); + 第一个参数时cls, cls代表的是类本身。 + 可以通过类和对象去调用。 + +静态方法: + @staticmethod进行装饰; + 可以通过类和对象去调用。 + +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + def __init__(self, name, age, gender): + self.name = name + self.age = age + self.gender = gender + + # 实例方法 + def skill_01(self, skill_name): + print('{}会{}!'.format(self.name, skill_name)) + + # 实例方法 + def skill_02(self): + print('{}会爬树!'.format(self.name)) + + @classmethod + def class_method(cls): + print('这是一个类方法!') + print('打印cls', cls) + + @staticmethod + def static_method(): + print('这是一个静态方法!') + +# 通过对象调用实例方法 +kitty = Cat('hello kitty', 1, 'female') +kitty.skill_01('跳舞') +coffee = Cat('coffee cat', 2, 'male') +coffee.skill_02() +# 通过类迪调用实例方法 +# Cat.skill_02() # 报错:TypeError: skill_02() missing 1 required positional argument: 'self' +print('-------------------------') +# 通过类访问类方法:类名.类方法名 +Cat.class_method() +# 通过对象调用类方法:对象名.类方法名 +kitty.class_method() +print('-------------------------') +# 通过类访问静态方法:类名.类方法名 +Cat.static_method() +# 通过对象调用静态方法:对象名.类方法名 +kitty.static_method() + +5. 关于类方法,静态方法,实例方法的应用场景 +类方法:在方法内部只会使用到类属性。 +静态方法:方法内部既不会使用类相关的属性和方法, 也不会使用实例(对象)相关的属性和方法。 +实例方法:在方法内部会使用到对象相关的属性或方法,那么适合定义为对象方法。 +示例: +class Cat: + # 类属性 + leg = '四条腿' + tail = '长尾巴' + + def __init__(self, name, age, gender): + # 实例(对象)属性 + self.name = name + self.age = age + self.gender = gender + + # 实例方法 + def skill_01(self): + print('{}会跳舞!'.format(self.name)) + self.move() + def move(self): + print('快速移动') + + # 类方法 + @classmethod + def class_method(cls): + print('这是猫类的共同特征:{}{}!'.format(cls.leg, cls.tail)) + print('打印cls', cls) + + #静态方法 + @staticmethod + def static_method(): + print('里面的代码和类和对象没有太多相关性!') + +kitty = Cat('kitty', 1, 'female') +kitty.skill_01() + + + diff --git a/python27Class/LearningNotesTXT/Python/flora_0303_notes.txt b/python27Class/LearningNotesTXT/Python/flora_0303_notes.txt new file mode 100644 index 0000000..5110cc0 --- /dev/null +++ b/python27Class/LearningNotesTXT/Python/flora_0303_notes.txt @@ -0,0 +1,367 @@ +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******类属性的分类****** +类属性的分类: + 1. 公有属性:既可以在类内部使用,又可以在类的外部被调用。 + 2. 私有属性:使用双下划线开头。只能在类外部使用,在类外面无法被调用。 + +示例: +class Cat: + # 公有属性 + attr = 'I have tail' + # 私有属性 + __attr = 'I have 4 legs' + + def print_attr(self): + print('在类的内部访问公有属性', self.attr) + print('在类的内部访问公有属性', self.__attr) + +Kitty = Cat() + +print('在类的外部访问公有属性', Kitty.attr) + +# 在类外部调用私有属性会报错: AttributeError: 'Cat' object has no attribute '__attr' +# print('在类的外部访问公有属性', Kitty.__attr) + +Kitty.print_attr() + +******类定义的两种方式****** +# 这两种定义类的方式无差别 +# 类定义的第一种方式:不写继承的父类,默认继承object。 +class MyTest: + pass + +# 类定义的第二种方式:在类名的括号后面指定继承object这个类。 +class MyClass(object): + pass + +# object: python中所有类的基类(祖宗类) +******类的继承****** +子类通过继承父类,能够获取父类中定义的所有属性和方法(私有属性除外)。 +注意:父类不能使用子类的属性和方法。 + +继承的作用:简化代码,提高代码的重用性。 + +示例: +未用到继承之前的代码: +class PhoneV1(object): + def call(self): + print('打电话的功能') + +class PhoneV2(object): + def call(self): + print('打电话的功能') + + def listen_music(self): + print('听音乐的功能') + + def send_message(self): + print('发短信的功能') + +class PhoneV3(object): + def call(self): + print('打电话的功能') + + def listen_music(self): + print('听音乐的功能') + + def send_message(self): + print('发短信的功能') + + def we_chat(self): + print('聊微信的功能') + + def plag_game(self): + print('玩游戏的功能') + +用到继承之后的代码: +class PhoneV1(object): + def call(self): + print('打电话的功能') + +class PhoneV2(PhoneV1): + def listen_music(self): + print('听音乐的功能') + + def send_message(self): + print('发短信的功能') + +class PhoneV3(PhoneV2): + def we_chat(self): + print('聊微信的功能') + + def play_game(self): + print('玩游戏的功能') + +# v1对应的类 +print('------v1对应的类------') +v1 = PhoneV1() +v1.call() +# 父类不能调用子类的方法 +# v1.listen_music() # 报错:AttributeError: 'PhoneV1' object has no attribute 'listen_music' + +# v2对应的类 +print('------v2对应的类------') +v2 = PhoneV2() +# 子类可以调用父类的方法 +v2.call() +v2.listen_music() +v2.send_message() + +# v3对应的类 +print('------v3对应的类------') +v3 = PhoneV3() +v3.call() +v3.listen_music() +v3.send_message() +v3.we_chat() +v3.play_game() + +******重写父类方法****** +在子类中定义跟父类同名的方法就是重写父类方法。 +class PhoneV1(object): + def call(self): + print('打电话的功能') + +class PhoneV2(PhoneV1): + def listen_music(self): + print('听音乐的功能') + + def send_message(self): + print('发短信的功能') + # 重写父类的方法 + def call(self): + print('打视频电话的功能') + +class PhoneV3(PhoneV2): + def we_chat(self): + print('聊微信的功能') + + def play_game(self): + print('玩游戏的功能') + +print('------v1对应的类------') +v1 = PhoneV1() +v1.call() # 输出结果:打电话的功能 + +print('------v2对应的类------') +v2 = PhoneV2() +# 子类可以调用父类的方法 +v2.call() # 输出结果:打视频电话的功能 + +print('------v3对应的类------') +v3 = PhoneV3() +v3.call() # 输出结果:打视频电话的功能 + +******调用被重写的父类方法****** +方式一:父类名.方法名(self) +方式二:super().方法名 +示例: +class PhoneV1(object): + def call(self): + print('打电话的功能') + +class PhoneV2(PhoneV1): + def we_chat(self): + print('聊微信的功能') + + def play_game(self): + print('玩游戏的功能') + # 重写父类的方法 + def call(self): + print('打视频电话的功能') + print('**********接下来想打语音电话') + # 调用父类里面的call() + # 方式一:父类名.方法名(self) + PhoneV1.call(self) + # 方式二:super().方法名 + super().call() + +v2 = PhoneV2() +v2.call() + + +******super()的应用场景****** +主要是代码的扩展,扩展新功能。 +示例: +class MyClass: + def __init__(self, a, b): + self.a = a + self.b = b + + def number(self): + print('a+b=', self.a + self.b) + + +class MyClassV2(MyClass): + def number(self): + # 调用父类原有的方法 + super().number() + # 在原有方法的基础上扩展新功能 + print('a+b=', self.a / self.b) + + +m = MyClassV2(11, 22) +m.number() + + +******动态获取属性****** +getattr获取类属性: + 参数1:类 + 参数2:属性名 + 参数3:默认值。如果属性不存在,则返回该值 + +示例: +# 示例1 +class TestData: + url = 'http://www.baidu.com' + method = 'get' + +# getattr获取类属性 +res = getattr(TestData, 'url') +print(res) # 输出结果:http://www.baidu.com + +res1 = getattr(TestData, 'result', 'python') +print(res1) # 输出结果:python + +# 示例2: +class TestData: + url = 'http://www.baidu.com' + method = 'get' + +name = input('请输入你要获取的属性名:') + +# getattr获取类属性 +res = getattr(TestData, name, 'None') +print(res) # 输出结果:http://www.baidu.com + +******动态设置属性****** +setattr设置属性值: + 参数1:类 + 参数2:属性名 + 参数3:属性值 + +示例1: +# 类外面定义类属性 +# 方式一:类.属性名=属性值 +TestData.result = 'Pass' +print(TestData.result) + +# 方式二:动态setattr设置属性 +setattr(TestData, 'para', 'username') +print(TestData.para) # 输出结果:username + +示例2: +class TestData: + url = 'http://www.baidu.com' + method = 'get' + +# 将下面2个列表,title作为属性名,data作为属性值,一一对应起来 +title = ['name', 'age', 'gender'] +data = ['flora', 26, 'female'] + +# 以下方法是不可取的,会报错:AttributeError: type object 'TestData' has no attribute 'title' +# TestData.title[0] = data[0] +# print(TestData.title[0]) + +# setattr(TestData, title[0], data[0]) +# setattr(TestData, title[1], data[1]) +# setattr(TestData, title[2], data[2]) + +for i in range(len(title)): + setattr(TestData, title[i], data[i]) + +print(TestData.name, TestData.age, TestData.gender) +# 输出结果:flora 26 female + + +******动态删除属性****** +delattr动态删除属性: + 参数1:类 + 参数2:属性名 + +示例: +class TestData: + url = 'http://www.baidu.com' + method = 'get' + +# 方式一:关键字del +del TestData.url +print(TestData.url) # 报错:AttributeError: type object 'TestData' has no attribute 'url' + +# 方式二:delattr +name = input('请输入你要删除的属性:') +delattr(TestData, name) + +******判断属性是否存在****** +hasattr判断属性是否存在: + 参数1:类名 + 参数2:属性名 +如果属性存在,返回True;如果属性不存在,返回False +示例: +class TestData: + url = 'http://www.baidu.com' + method = 'get' + +del TestData.url + +res = hasattr(TestData, 'url') +print(res) # 输出结果:False +res1 = hasattr(TestData, 'method') +print(res1) # 输出结果:True + +******多继承****** +子类可以继承多个父类,子类都可以用到继承的父类中的属性和方法。 +示例: +class BaseA(object): + attr_a = 100 + def func_a(self): + print('func_a----------aaa') + +class BaseB(object): + attr_b = 900 + def func_b(self): + print('func_b----------bbb') + +class MyTest(BaseA, BaseB): + pass + +m = MyTest() +print(m.attr_a) +print(m.attr_b) + +m.func_a() +m.func_b() + +注意: +如果子类继承的父类里面都有相同的方法,在调用的时候,会先找第一个父类的方法,找到了就不会继续找了,没找到就会继续找下一个父类的方法。 +如果子类自己也有跟父类相同的方法,在调用的时候,子类会优先使用自己的方法,不会去找父类的方法了。 +示例: +class BaseA(object): + attr_a = 100 + def func_a(self): + print('func_a----------aaa') + + def func(self): + print('func_ab----------ab') + +class BaseB(object): + attr_b = 900 + def func_b(self): + print('func_b----------bbb') + + def func(self): + print('func_bb----------bb') + +class MyTest(BaseA, BaseB): + pass + # def func(self): + # print('func_cb----------cb') + +m = MyTest() +m.func() + diff --git a/python27Class/class03052020/README.txt b/python27Class/class03052020/README.txt new file mode 100644 index 0000000..ab8d070 --- /dev/null +++ b/python27Class/class03052020/README.txt @@ -0,0 +1,4 @@ +本次课程的内容: +1. 初步学习unittest +2. 学习如何编写测试用例 +3. 学习如何通过测试套件运行测试,并生成HTML测试报告 \ No newline at end of file diff --git a/python27Class/class03052020/login.py b/python27Class/class03052020/login.py new file mode 100644 index 0000000..e1d5352 --- /dev/null +++ b/python27Class/class03052020/login.py @@ -0,0 +1,21 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:42 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +def login_check(username=None, passwd=None): + """ + 登录校验的函数 + :param username: + :param passwd: + :return: dict type + """ + if username != None and passwd != None: + if username == 'flora' and passwd == '1234567Az': + return {'code': 0, 'mag': '登录成功'} + else: + return {'code': 1, 'mag': '账号或者密码不正确'} + else: + return {'code': 1, 'mag': '账号和密码不能为空'} \ No newline at end of file diff --git a/python27Class/class03052020/runTest.py b/python27Class/class03052020/runTest.py new file mode 100644 index 0000000..e1c56dc --- /dev/null +++ b/python27Class/class03052020/runTest.py @@ -0,0 +1,82 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 21:11 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +import unittest + +""" +第一步:创建测试套件 +""" +suite = unittest.TestSuite() + +""" +第二步:加载测试用例到测试套件 +""" +# 第一种:通过测试用例类去加载 +# from python27Class.testCase import LoginTestCase +# loader = unittest.TestLoader() +# suite.addTest(loader.loadTestsFromTestCase(LoginTestCase)) + +# 第二种:通过测试用例模块去加载 +# 用例加载器对象 +# from python27Class import testCase +# loader = unittest.TestLoader() +# suite.addTest(loader.loadTestsFromModule(testCase)) + +# 第三种:通过路径去加载所有的测试用例 (推荐这一种) +# 注意:默认去找指定路径中test开头的模块中的测试用例 +# loader = unittest.TestLoader() +# suite.addTest(loader.discover(r'E:\PycharmProject\PythonClassChy\python27Class')) + +# 第四种:一条条去加载 +from python27Class.class03052020.testCase import LoginTestCase +case1 = LoginTestCase('test_login_pass') +suite.addTest(case1) + +""" +综合第一步和第二步:创建套件并加载用例 +""" +# suite = unittest.defaultTestLoader.discover(r'E:\PycharmProject\PythonClassChy\python27Class') + +""" +第三步:(1)执行测试套件中的用例, 控制台生成报告 +""" +# 仅执行,未生成测试报告 +# 创建测试运行程序 +runner = unittest.TextTestRunner() +runner.run(suite) + +# ---------------------------------------------- +# 执行并生成测试报告 +""" +第三步:(2)使用BeautifulReport来执行测试套件中的用例并生成报告 +# 2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 + +需要注释这两行代码: +# runner = unittest.TextTestRunner() +# runner.run(suite) +否则运行生成报告的代码会报错:TypeError: 'NoneType' object is not callable +""" +# from BeautifulReport import BeautifulReport +# br = BeautifulReport(suite) +# br.report('flora Auto-Test Report', 'brReport.html', report_dir=r'E:\PycharmProject\PythonClassChy\python27Class\testReport') + +# ---------------------------------------------- +""" +第三步:(3)使用HTMLTestRunner来生成测试报告 +stream表示报告存放的位置以及写入的模式 +title表示报告的标题 +tester表示测试人员 +description表示对测试报告的描述 +""" +# from HTMLTestRunner import HTMLTestRunner +# runner = HTMLTestRunner(stream=open(r'E:\PycharmProject\PythonClassChy\python27Class\testReport\newReport.html', 'wb'), +# title='flora Auto-Test Report', +# tester='flora', +# description='第一个版本的测试') +# runner.run(suite) diff --git a/python27Class/class03052020/testCase.py b/python27Class/class03052020/testCase.py new file mode 100644 index 0000000..d0f8c2e --- /dev/null +++ b/python27Class/class03052020/testCase.py @@ -0,0 +1,83 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:23 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.class03052020.login import login_check + +""" +# 定义测试用例类:必须继承unittest.TestCase +# 定义测试用例:在测试用例类中,每一个以test开头的方法就是一条用例 +# unittest中测试用例执行的顺序,是根据方法名按ASCII码进行排序的 +# unittest中会自动根据用例方法执行的时候,是否出现断言异常来评判用例执行是否通过 +""" +class LoginTestCase(unittest.TestCase): + # 第一步:准备用例数据 + # 第二步:获取实际结果(调用功能函数,传入参数,获取实际结果) + # 第三步:断言(比对预期结果和实际结果) + def test_login_pass(self): + # 参数准备 + data = {'username': 'flora', 'passwd': '1234567Az'} + # 预期结果准备 + expect_result = {'code': 0, 'mag': '登录成功'} + # 获取实际结果 + actual_result = login_check(**data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) + + + def test_login_user_error(self): + # 参数准备 + data = {'username': 'flora.chen', 'passwd': '1234567Az'} + # 预期结果准备 + expect_result = {'code': 1, 'mag': '账号或者密码不正确'} + # 获取实际结果 + actual_result = login_check(**data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) + + def test_login_pwd_error(self): + # 参数准备 + data = {'username': 'flora', 'passwd': '1234567Aa'} + # 预期结果准备 + expect_result = {'code': 1, 'mag': '账号或者密码不正确'} + # 获取实际结果 + actual_result = login_check(**data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) + + def test_login_user_is_null(self): + # 参数准备 + data = {'passwd': '1234567Aa'} + # 预期结果准备 + expect_result = {'code': 1, 'mag': '账号和密码不能为空'} + # 获取实际结果 + actual_result = login_check(**data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) + + def test_login_pwd_is_null(self): + # 参数准备 + data = {'username': 'flora'} + # 预期结果准备 + expect_result = {'code': 1, 'mag': '账号和密码不能为空'} + # 获取实际结果 + actual_result = login_check(**data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) + +if __name__ == '__main__': + unittest.main() + + + + diff --git a/python27Class/class03072020/README.txt b/python27Class/class03072020/README.txt new file mode 100644 index 0000000..f628da8 --- /dev/null +++ b/python27Class/class03072020/README.txt @@ -0,0 +1,3 @@ +本次课程的内容: +1. 学习unittest的数据驱动DDT +2. 学习如何读取excel中的数据以及往excel中写入数据 \ No newline at end of file diff --git a/python27Class/class03072020/demo1/noteDemo1.txt b/python27Class/class03072020/demo1/noteDemo1.txt new file mode 100644 index 0000000..d789839 --- /dev/null +++ b/python27Class/class03072020/demo1/noteDemo1.txt @@ -0,0 +1,3 @@ +用例数据从用例中分离出来。 +这种方式不用写多个测试用例。减少代码的冗余。 +可以通过传一组数据的方式,通过一个test case方法来执行。 diff --git a/python27Class/class03072020/demo1/registerPage.py b/python27Class/class03072020/demo1/registerPage.py new file mode 100644 index 0000000..02a9215 --- /dev/null +++ b/python27Class/class03072020/demo1/registerPage.py @@ -0,0 +1,68 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 8:59 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +users = [{'user': 'python26', 'password': '123456'}] + + +def register(username, password1, password2): + """ + + :param username: + :param password1: + :param password2: + :return: + """ + # 判断是否有参数为空 + if not all([username, password1, password2]): + return {"code": 0, "msg": "所有参数不能为空"} + # 注册功能 + for user in users: # 遍历出所有账号,判断账号是否存在 + if username == user['user']: + # 账号存在 + return {"code": 0, "msg": "该账户已存在"} + else: + if password1 != password2: + # 两次密码不一致 + return {"code": 0, "msg": "两次密码不一致"} + else: + # 账号不存在 密码不重复,判断账号密码长度是否在 6-18位之间 + if 6 <= len(username) >= 6 and 6 <= len(password1) <= 18: + # 注册账号 + users.append({'user': username, 'password': password2}) + return {"code": 1, "msg": "注册成功"} + else: + # 账号密码长度不对,注册失败 + return {"code": 0, "msg": "账号和密码必须在6-18位之间"} + + +if __name__ == "__main__": + res = register('python14', '123456', '123456') + print(res) + +""" +函数入参: +注意:参数传字符串类型,不需要考虑其他类型。 +参数1:账号 +参数2:密码1 +参数2:密码2 + + +函数内部处理的逻辑: + 判断是否有参数为空, + 判断账号密码是否在6-18位之间, + 判断账号是否被注册过, + 判断两个密码是否一致。 + 上面添加都校验通过才能注册成功,其他情况都注册失败, +各种情况的返回结果如下: + 注册成功 返回结果:{"code": 1, "msg": "注册成功"} + 有参数为空, 返回结果 {"code": 0, "msg": "所有参数不能为空"} + 两次密码不一致 返回结果:{"code": 0, "msg": "两次密码不一致"} + 账户已存在 返回结果:{"code": 0, "msg": "该账户已存在"} + 密码不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} + 账号不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} +""" \ No newline at end of file diff --git a/python27Class/class03072020/demo1/runTest.py b/python27Class/class03072020/demo1/runTest.py new file mode 100644 index 0000000..a6bfbd6 --- /dev/null +++ b/python27Class/class03072020/demo1/runTest.py @@ -0,0 +1,54 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 9:33 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import os +import unittest + +from BeautifulReport import BeautifulReport + +from python27Class.class03072020.demo1.testRegister import RegisterTestCase + +""" +第一步:创建测试套件 +""" +suite = unittest.TestSuite() + +""" +第二步:(1)加载测试用例(执行单条测试用例数据) +case_data = {'expect_result': {"code": 0, "msg": "该账户已存在"}, 'data': ['python26', '123456', '123456']} +case = RegisterTestCase('test_register', case_data) +suite.addTest(case) +""" + +""" +第二步:(2)加载测试用例(执行多条测试用例数据) +""" +cases = [ + {'expect_result': {"code": 0, "msg": "该账户已存在"}, 'data': ['python26', '123456', '123456']}, + {'expect_result': {"code": 0, "msg": "两次密码不一致"}, 'data': ['python1', '12345655', '123456']}, +] +for case_data in cases: + case = RegisterTestCase('test_register', case_data) + suite.addTest(case) + + +""" +第三步:执行测试套件中的用例, 使用BeautifulReport生成HTML测试报告 +2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" +# 要执行的测试用例的位置 +path = os.path.dirname(os.path.abspath(__file__)) + +# 测试报告存放的路径 +report_path = os.path.join(path, 'testReport') + +b_report = BeautifulReport(suite) +b_report.report('Register Function Report by flora', + 'register_beautiful_report.html', + report_dir=report_path + ) diff --git a/python27Class/class03072020/demo1/testRegister.py b/python27Class/class03072020/demo1/testRegister.py new file mode 100644 index 0000000..f938d8b --- /dev/null +++ b/python27Class/class03072020/demo1/testRegister.py @@ -0,0 +1,27 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 9:47 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.class03072020.demo1.registerPage import register + + +class RegisterTestCase(unittest.TestCase): + def __init__(self, methodName, case_data): + super().__init__(methodName) + self.case_data = case_data + + def test_register(self): + # 参数准备 + data = self.case_data['data'] + # 预期结果准备 + expect_result = self.case_data['expect_result'] + # 获取实际结果 + actual_result = register(*data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) diff --git a/python27Class/class03072020/demo2/ddtNew.py b/python27Class/class03072020/demo2/ddtNew.py new file mode 100644 index 0000000..2915330 --- /dev/null +++ b/python27Class/class03072020/demo2/ddtNew.py @@ -0,0 +1,319 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 10:52 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +# -*- coding: utf-8 -*- +# This file is a part of DDT (https://github.com/datadriventests/ddt) +# Copyright 2012-2015 Carles Barrobés and DDT contributors +# For the exact contribution history, see the git revision log. +# DDT is licensed under the MIT License, included in +# https://github.com/datadriventests/ddt/blob/master/LICENSE.md + +import inspect +import json +import os +import re +import codecs +from functools import wraps + +try: + import yaml +except ImportError: # pragma: no cover + _have_yaml = False +else: + _have_yaml = True + +__version__ = '1.2.2' + +# These attributes will not conflict with any real python attribute +# They are added to the decorated test method and processed later +# by the `ddt` class decorator. + +DATA_ATTR = '%values' # store the data the test must run with +FILE_ATTR = '%file_path' # store the path to JSON file +UNPACK_ATTR = '%unpack' # remember that we have to unpack values +index_len = 5 # default max length of case index + + +try: + trivial_types = (type(None), bool, int, float, basestring) +except NameError: + trivial_types = (type(None), bool, int, float, str) + + +def is_trivial(value): + if isinstance(value, trivial_types): + return True + elif isinstance(value, (list, tuple)): + return all(map(is_trivial, value)) + return False + + +def unpack(func): + """ + Method decorator to add unpack feature. + + """ + setattr(func, UNPACK_ATTR, True) + return func + + +def data(*values): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + global index_len + index_len = len(str(len(values))) + return idata(values) + + +def idata(iterable): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + def wrapper(func): + setattr(func, DATA_ATTR, iterable) + return func + return wrapper + + +def file_data(value): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + ``value`` should be a path relative to the directory of the file + containing the decorated ``unittest.TestCase``. The file + should contain JSON encoded data, that can either be a list or a + dict. + + In case of a list, each value in the list will correspond to one + test case, and the value will be concatenated to the test method + name. + + In case of a dict, keys will be used as suffixes to the name of the + test case, and values will be fed as test data. + + """ + def wrapper(func): + setattr(func, FILE_ATTR, value) + return func + return wrapper + + +def mk_test_name(name, value, index=0): + """ + Generate a new name for a test case. + + It will take the original test name and append an ordinal index and a + string representation of the value, and convert the result into a valid + python identifier by replacing extraneous characters with ``_``. + + We avoid doing str(value) if dealing with non-trivial values. + The problem is possible different names with different runs, e.g. + different order of dictionary keys (see PYTHONHASHSEED) or dealing + with mock objects. + Trivial scalar values are passed as is. + + A "trivial" value is a plain scalar, or a tuple or list consisting + only of trivial values. + """ + + # Add zeros before index to keep order + index = "{0:0{1}}".format(index + 1, index_len) + if not is_trivial(value): + return "{0}_{1}".format(name, index) + try: + value = str(value) + except UnicodeEncodeError: + # fallback for python2 + value = value.encode('ascii', 'backslashreplace') + test_name = "{0}_{1}_{2}".format(name, index, value) + return re.sub(r'\W|^(?=\d)', '_', test_name) + + +def feed_data(func, new_name, test_data_docstring, *args, **kwargs): + """ + This internal method decorator feeds the test data item to the test. + + """ + @wraps(func) + def wrapper(self): + return func(self, *args, **kwargs) + wrapper.__name__ = new_name + wrapper.__wrapped__ = func + # set docstring if exists + if test_data_docstring is not None: + wrapper.__doc__ = test_data_docstring + else: + # Try to call format on the docstring + if func.__doc__: + try: + wrapper.__doc__ = func.__doc__.format(*args, **kwargs) + except (IndexError, KeyError): + # Maybe the user has added some of the formating strings + # unintentionally in the docstring. Do not raise an exception + # as it could be that user is not aware of the + # formating feature. + pass + return wrapper + + +def add_test(cls, test_name, test_docstring, func, *args, **kwargs): + """ + Add a test case to this class. + + The test will be based on an existing function but will give it a new + name. + + """ + setattr(cls, test_name, feed_data(func, test_name, test_docstring, + *args, **kwargs)) + + +def process_file_data(cls, name, func, file_attr): + """ + Process the parameter in the `file_data` decorator. + """ + cls_path = os.path.abspath(inspect.getsourcefile(cls)) + data_file_path = os.path.join(os.path.dirname(cls_path), file_attr) + + def create_error_func(message): # pylint: disable-msg=W0613 + def func(*args): + raise ValueError(message % file_attr) + return func + + # If file does not exist, provide an error function instead + if not os.path.exists(data_file_path): + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test(cls, test_name, test_docstring, + create_error_func("%s does not exist"), None) + return + + _is_yaml_file = data_file_path.endswith((".yml", ".yaml")) + + # Don't have YAML but want to use YAML file. + if _is_yaml_file and not _have_yaml: + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test( + cls, + test_name, + test_docstring, + create_error_func("%s is a YAML file, please install PyYAML"), + None + ) + return + + with codecs.open(data_file_path, 'r', 'utf-8') as f: + # Load the data from YAML or JSON + if _is_yaml_file: + data = yaml.safe_load(f) + else: + data = json.load(f) + + _add_tests_from_data(cls, name, func, data) + + +def _add_tests_from_data(cls, name, func, data): + """ + Add tests from data loaded from the data file into the class + """ + for i, elem in enumerate(data): + if isinstance(data, dict): + key, value = elem, data[elem] + test_name = mk_test_name(name, key, i) + elif isinstance(data, list): + value = elem + test_name = mk_test_name(name, value, i) + if isinstance(value, dict): + add_test(cls, test_name, test_name, func, **value) + else: + add_test(cls, test_name, test_name, func, value) + + +def _is_primitive(obj): + """Finds out if the obj is a "primitive". It is somewhat hacky but it works. + """ + return not hasattr(obj, '__dict__') + + +def _get_test_data_docstring(func, value): + """Returns a docstring based on the following resolution strategy: + 1. Passed value is not a "primitive" and has a docstring, then use it. + 2. In all other cases return None, i.e the test name is used. + """ + if not _is_primitive(value) and value.__doc__: + return value.__doc__ + else: + return None + + +def ddt(cls): + """ + Class decorator for subclasses of ``unittest.TestCase``. + + Apply this decorator to the test case class, and then + decorate test methods with ``@data``. + + For each method decorated with ``@data``, this will effectively create as + many methods as data items are passed as parameters to ``@data``. + + The names of the test methods follow the pattern + ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the + data argument, starting with 1. + + For data we use a string representation of the data value converted into a + valid python identifier. If ``data.__name__`` exists, we use that instead. + + For each method decorated with ``@file_data('test_data.json')``, the + decorator will try to load the test_data.json file located relative + to the python file containing the method that is decorated. It will, + for each ``test_name`` key create as many methods in the list of values + from the ``data`` key. + + """ + for name, func in list(cls.__dict__.items()): + if hasattr(func, DATA_ATTR): + for i, v in enumerate(getattr(func, DATA_ATTR)): + test_name = mk_test_name(name, getattr(v, "__name__", v), i) + # 将用例描述信息改为用例数据的title字段 + # 原代码:test_data_docstring = _get_test_data_docstring(func, v) + test_data_docstring = v['title'] + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) + else: + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls diff --git a/python27Class/class03072020/demo2/noteDemo2.txt b/python27Class/class03072020/demo2/noteDemo2.txt new file mode 100644 index 0000000..0c5fb9c --- /dev/null +++ b/python27Class/class03072020/demo2/noteDemo2.txt @@ -0,0 +1,17 @@ +先安装数据驱动 +pip install ddt +DDT会自动遍历用例数据。 +----------------------------------------------------------- +DDT执行用例后生成的报告,会在方法名后加编号,例如:test_register_1。 +----------------------------------------------------------- +但是如果需要显示每条用例执行时验证了什么功能,需要修改DDT原码。 +可以将DDT原码复制出来做如下修改: +ddt.py中第284行代码:test_data_docstring = _get_test_data_docstring(func, v) + +用例数据中需要传入title: + cases = [ + {'title': '该账户已存在', 'expect_result': {"code": 0, "msg": "该账户已存在"}, 'data': ['python26', '123456', '123456']}, + {'title': '两次密码不一致', 'expect_result': {"code": 0, "msg": "两次密码不一致"}, 'data': ['python1', '12345655', '123456']}, + ] + +然后倒入ddt的时候, 需要导入我们新修改的ddt模块 \ No newline at end of file diff --git a/python27Class/class03072020/demo2/registerPage.py b/python27Class/class03072020/demo2/registerPage.py new file mode 100644 index 0000000..02a9215 --- /dev/null +++ b/python27Class/class03072020/demo2/registerPage.py @@ -0,0 +1,68 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 8:59 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +users = [{'user': 'python26', 'password': '123456'}] + + +def register(username, password1, password2): + """ + + :param username: + :param password1: + :param password2: + :return: + """ + # 判断是否有参数为空 + if not all([username, password1, password2]): + return {"code": 0, "msg": "所有参数不能为空"} + # 注册功能 + for user in users: # 遍历出所有账号,判断账号是否存在 + if username == user['user']: + # 账号存在 + return {"code": 0, "msg": "该账户已存在"} + else: + if password1 != password2: + # 两次密码不一致 + return {"code": 0, "msg": "两次密码不一致"} + else: + # 账号不存在 密码不重复,判断账号密码长度是否在 6-18位之间 + if 6 <= len(username) >= 6 and 6 <= len(password1) <= 18: + # 注册账号 + users.append({'user': username, 'password': password2}) + return {"code": 1, "msg": "注册成功"} + else: + # 账号密码长度不对,注册失败 + return {"code": 0, "msg": "账号和密码必须在6-18位之间"} + + +if __name__ == "__main__": + res = register('python14', '123456', '123456') + print(res) + +""" +函数入参: +注意:参数传字符串类型,不需要考虑其他类型。 +参数1:账号 +参数2:密码1 +参数2:密码2 + + +函数内部处理的逻辑: + 判断是否有参数为空, + 判断账号密码是否在6-18位之间, + 判断账号是否被注册过, + 判断两个密码是否一致。 + 上面添加都校验通过才能注册成功,其他情况都注册失败, +各种情况的返回结果如下: + 注册成功 返回结果:{"code": 1, "msg": "注册成功"} + 有参数为空, 返回结果 {"code": 0, "msg": "所有参数不能为空"} + 两次密码不一致 返回结果:{"code": 0, "msg": "两次密码不一致"} + 账户已存在 返回结果:{"code": 0, "msg": "该账户已存在"} + 密码不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} + 账号不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} +""" \ No newline at end of file diff --git a/python27Class/class03072020/demo2/runTest.py b/python27Class/class03072020/demo2/runTest.py new file mode 100644 index 0000000..03c9686 --- /dev/null +++ b/python27Class/class03072020/demo2/runTest.py @@ -0,0 +1,38 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 9:33 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import os +import unittest + +from BeautifulReport import BeautifulReport + +from python27Class.class03072020.demo1.testRegister import RegisterTestCase + +""" +第一步:创建测试套件并加载测试用例 +""" +# 要执行的测试用例的位置 +path = os.path.dirname(os.path.abspath(__file__)) + +suite = unittest.defaultTestLoader.discover(path) + + +""" +第二步:执行测试套件中的用例, 使用BeautifulReport生成HTML测试报告 +2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" + + +# 测试报告存放的路径 +report_path = os.path.join(path, 'testReport') + +b_report = BeautifulReport(suite) +b_report.report('Register Function Report by flora', + 'register_beautiful_report.html', + report_dir=report_path + ) diff --git a/python27Class/class03072020/demo2/testRegister.py b/python27Class/class03072020/demo2/testRegister.py new file mode 100644 index 0000000..f86cd8c --- /dev/null +++ b/python27Class/class03072020/demo2/testRegister.py @@ -0,0 +1,30 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 9:47 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.class03072020.demo2.registerPage import register +from python27Class.class03072020.demo2.ddtNew import ddt, data + +@ddt +class RegisterTestCase(unittest.TestCase): + cases = [ + {'title': '该账户已存在', 'expect_result': {"code": 0, "msg": "该账户已存在"}, 'data': ['python26', '123456', '123456']}, + {'title': '两次密码不一致', 'expect_result': {"code": 0, "msg": "两次密码不一致"}, 'data': ['python1', '12345655', '123456']}, + ] + + @data(*cases) + def test_register(self, case): + # 参数准备 + data = case['data'] + # 预期结果准备 + expect_result = case['expect_result'] + # 获取实际结果 + actual_result = register(*data) + # 断言 + # assert expect_result == actual_result + self.assertEqual(expect_result, actual_result) diff --git a/python27Class/class03072020/demo2/testReport/register_beautiful_report.html b/python27Class/class03072020/demo2/testReport/register_beautiful_report.html new file mode 100644 index 0000000..0876ea3 --- /dev/null +++ b/python27Class/class03072020/demo2/testReport/register_beautiful_report.html @@ -0,0 +1,7360 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/class03072020/demo3/case.xlsx b/python27Class/class03072020/demo3/case.xlsx new file mode 100644 index 0000000..52c0c27 Binary files /dev/null and b/python27Class/class03072020/demo3/case.xlsx differ diff --git a/python27Class/class03072020/demo3/noteDemo3.txt b/python27Class/class03072020/demo3/noteDemo3.txt new file mode 100644 index 0000000..a86144a --- /dev/null +++ b/python27Class/class03072020/demo3/noteDemo3.txt @@ -0,0 +1,7 @@ +pip install openpyxl + +新建一个xlsx格式的excel,将用例数据放在表格中 + +Excel的三大对象 +workbook: 工作簿对象 + diff --git a/python27Class/class03072020/demo3/pythonExcel.py b/python27Class/class03072020/demo3/pythonExcel.py new file mode 100644 index 0000000..02c1e4a --- /dev/null +++ b/python27Class/class03072020/demo3/pythonExcel.py @@ -0,0 +1,76 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 11:03 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl + +# 将指定的excel文件加载为一个workbook对象 +wb = openpyxl.load_workbook('case.xlsx') + +# 选中工作簿中的表单对象 +sh = wb['case'] + + +# # 读取指定格子中的数据 +# c12 = sh.cell(row=1, column=2).value # 表示获取第一行第二列的数据 +# +# # 写入数据 +# sh.cell(row=3, column=1, value='flora') +# # 将工作簿对象保存为文件 +wb.save('case.xlsx') + +# 获取表单中的最大行 +max_row = sh.max_row +print(max_row) + +# 获取表单中的最大列 +max_column= sh.max_column +print(max_column) + +# rows按行获取整个表单里面的所有格子对象,每行的内容放在一个元组中 +""" +[(, , +, ), +(, , +, )] +""" +res1 = list(sh.rows) +print(res1) + +# 通过for循环获取每行中的内容 +for item in res1: + for i in item: + print(i.value) + +# columns按列获取整个表单里面的所有格子对象,每行的内容放在一个元组中 +""" +[(, ), +(, ), +(, ), +(, )] +""" +res2 = list(sh.columns) +print(res2) + +# 通过for循环获取每列中的内容 +for item in res2: + for j in item: + print(j.value) + +print('------------------') +# 读取第三行的数据 +res3 = list(sh.rows) +print(res3[2]) +for i in res3[2]: + print(i.value) + + +# 读取第二列到第四列的内容 +res4 = list(sh.columns) +print(res4[1:3]) +for j in res4[1:3]: + for i in j: + print(i.value) \ No newline at end of file diff --git a/python27Class/class03102020/README.txt b/python27Class/class03102020/README.txt new file mode 100644 index 0000000..1bf2c7d --- /dev/null +++ b/python27Class/class03102020/README.txt @@ -0,0 +1,3 @@ +本次课程的内容: +1. 将从excel读取用例数据的操作封装在一个readExcel的模块中 +2. 执行测试的过程中,将测试结果回写到excel中 \ No newline at end of file diff --git a/python27Class/class03102020/demo1/readExcelNotClass.py b/python27Class/class03102020/demo1/readExcelNotClass.py new file mode 100644 index 0000000..1e9993a --- /dev/null +++ b/python27Class/class03102020/demo1/readExcelNotClass.py @@ -0,0 +1,59 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/10 20:51 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl +# 创建一个空列表,用来存放所有的用例数据 +case_data = [] + +wb = openpyxl.load_workbook('cases.xlsx') +# 选择表单 +sh = wb['register'] +# 按行获取所有数据 +datas = list(sh.rows) + +# --------------单行数据打包------------------ +# 获取第一行数据(表头), 保存到title这个列表中 +# print(datas[0]) +# title = [] +# for item in datas[0]: +# print(item.value) +# title.append(item.value) +# # print(title) +# +# # 读取第二行 +# values = [] +# for item in datas[1]: +# values.append(item.value) +# # print(values) +# +# case = dict(zip(title, values)) +# case_data.append(case) +# print(case_data) +# -------------------------------- + +# --------------多行数据打包------------------ +# 获取第一行数据(表头), 保存到title这个列表中 +print(datas[0]) +title = [] +for item in datas[0]: + title.append(item.value) + +# 使用切片的方式,遍历除了第一行之外的行的数据 +for item in datas[1:]: + # 每遍历出来一行数据就创建一个空列表来存放该行数据 + values = [] + # 遍历该行每个单元格的对象,获取单元格中的数据值存放到values列表中 + for i in item: + values.append(i.value) + # 每遍历完一行数据就拿该行的数据跟title表头打包转换为字典 + case = dict(zip(title, values)) + # 将该行用例数据追加到case_data列表中 + case_data.append(case) + print(case_data) +# -------------------------------- +# 注意:从excel中读取出来的数据除了数值,其他的不管保存的是什么格式,读取出来的都是字符串。 +# 读取出来的数据可以在使用的时候使用eval来转换一下。 \ No newline at end of file diff --git a/python27Class/class03102020/demo2/cases.xlsx b/python27Class/class03102020/demo2/cases.xlsx new file mode 100644 index 0000000..0d804be Binary files /dev/null and b/python27Class/class03102020/demo2/cases.xlsx differ diff --git a/python27Class/class03102020/demo2/ddtNew.py b/python27Class/class03102020/demo2/ddtNew.py new file mode 100644 index 0000000..2915330 --- /dev/null +++ b/python27Class/class03102020/demo2/ddtNew.py @@ -0,0 +1,319 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 10:52 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +# -*- coding: utf-8 -*- +# This file is a part of DDT (https://github.com/datadriventests/ddt) +# Copyright 2012-2015 Carles Barrobés and DDT contributors +# For the exact contribution history, see the git revision log. +# DDT is licensed under the MIT License, included in +# https://github.com/datadriventests/ddt/blob/master/LICENSE.md + +import inspect +import json +import os +import re +import codecs +from functools import wraps + +try: + import yaml +except ImportError: # pragma: no cover + _have_yaml = False +else: + _have_yaml = True + +__version__ = '1.2.2' + +# These attributes will not conflict with any real python attribute +# They are added to the decorated test method and processed later +# by the `ddt` class decorator. + +DATA_ATTR = '%values' # store the data the test must run with +FILE_ATTR = '%file_path' # store the path to JSON file +UNPACK_ATTR = '%unpack' # remember that we have to unpack values +index_len = 5 # default max length of case index + + +try: + trivial_types = (type(None), bool, int, float, basestring) +except NameError: + trivial_types = (type(None), bool, int, float, str) + + +def is_trivial(value): + if isinstance(value, trivial_types): + return True + elif isinstance(value, (list, tuple)): + return all(map(is_trivial, value)) + return False + + +def unpack(func): + """ + Method decorator to add unpack feature. + + """ + setattr(func, UNPACK_ATTR, True) + return func + + +def data(*values): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + global index_len + index_len = len(str(len(values))) + return idata(values) + + +def idata(iterable): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + def wrapper(func): + setattr(func, DATA_ATTR, iterable) + return func + return wrapper + + +def file_data(value): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + ``value`` should be a path relative to the directory of the file + containing the decorated ``unittest.TestCase``. The file + should contain JSON encoded data, that can either be a list or a + dict. + + In case of a list, each value in the list will correspond to one + test case, and the value will be concatenated to the test method + name. + + In case of a dict, keys will be used as suffixes to the name of the + test case, and values will be fed as test data. + + """ + def wrapper(func): + setattr(func, FILE_ATTR, value) + return func + return wrapper + + +def mk_test_name(name, value, index=0): + """ + Generate a new name for a test case. + + It will take the original test name and append an ordinal index and a + string representation of the value, and convert the result into a valid + python identifier by replacing extraneous characters with ``_``. + + We avoid doing str(value) if dealing with non-trivial values. + The problem is possible different names with different runs, e.g. + different order of dictionary keys (see PYTHONHASHSEED) or dealing + with mock objects. + Trivial scalar values are passed as is. + + A "trivial" value is a plain scalar, or a tuple or list consisting + only of trivial values. + """ + + # Add zeros before index to keep order + index = "{0:0{1}}".format(index + 1, index_len) + if not is_trivial(value): + return "{0}_{1}".format(name, index) + try: + value = str(value) + except UnicodeEncodeError: + # fallback for python2 + value = value.encode('ascii', 'backslashreplace') + test_name = "{0}_{1}_{2}".format(name, index, value) + return re.sub(r'\W|^(?=\d)', '_', test_name) + + +def feed_data(func, new_name, test_data_docstring, *args, **kwargs): + """ + This internal method decorator feeds the test data item to the test. + + """ + @wraps(func) + def wrapper(self): + return func(self, *args, **kwargs) + wrapper.__name__ = new_name + wrapper.__wrapped__ = func + # set docstring if exists + if test_data_docstring is not None: + wrapper.__doc__ = test_data_docstring + else: + # Try to call format on the docstring + if func.__doc__: + try: + wrapper.__doc__ = func.__doc__.format(*args, **kwargs) + except (IndexError, KeyError): + # Maybe the user has added some of the formating strings + # unintentionally in the docstring. Do not raise an exception + # as it could be that user is not aware of the + # formating feature. + pass + return wrapper + + +def add_test(cls, test_name, test_docstring, func, *args, **kwargs): + """ + Add a test case to this class. + + The test will be based on an existing function but will give it a new + name. + + """ + setattr(cls, test_name, feed_data(func, test_name, test_docstring, + *args, **kwargs)) + + +def process_file_data(cls, name, func, file_attr): + """ + Process the parameter in the `file_data` decorator. + """ + cls_path = os.path.abspath(inspect.getsourcefile(cls)) + data_file_path = os.path.join(os.path.dirname(cls_path), file_attr) + + def create_error_func(message): # pylint: disable-msg=W0613 + def func(*args): + raise ValueError(message % file_attr) + return func + + # If file does not exist, provide an error function instead + if not os.path.exists(data_file_path): + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test(cls, test_name, test_docstring, + create_error_func("%s does not exist"), None) + return + + _is_yaml_file = data_file_path.endswith((".yml", ".yaml")) + + # Don't have YAML but want to use YAML file. + if _is_yaml_file and not _have_yaml: + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test( + cls, + test_name, + test_docstring, + create_error_func("%s is a YAML file, please install PyYAML"), + None + ) + return + + with codecs.open(data_file_path, 'r', 'utf-8') as f: + # Load the data from YAML or JSON + if _is_yaml_file: + data = yaml.safe_load(f) + else: + data = json.load(f) + + _add_tests_from_data(cls, name, func, data) + + +def _add_tests_from_data(cls, name, func, data): + """ + Add tests from data loaded from the data file into the class + """ + for i, elem in enumerate(data): + if isinstance(data, dict): + key, value = elem, data[elem] + test_name = mk_test_name(name, key, i) + elif isinstance(data, list): + value = elem + test_name = mk_test_name(name, value, i) + if isinstance(value, dict): + add_test(cls, test_name, test_name, func, **value) + else: + add_test(cls, test_name, test_name, func, value) + + +def _is_primitive(obj): + """Finds out if the obj is a "primitive". It is somewhat hacky but it works. + """ + return not hasattr(obj, '__dict__') + + +def _get_test_data_docstring(func, value): + """Returns a docstring based on the following resolution strategy: + 1. Passed value is not a "primitive" and has a docstring, then use it. + 2. In all other cases return None, i.e the test name is used. + """ + if not _is_primitive(value) and value.__doc__: + return value.__doc__ + else: + return None + + +def ddt(cls): + """ + Class decorator for subclasses of ``unittest.TestCase``. + + Apply this decorator to the test case class, and then + decorate test methods with ``@data``. + + For each method decorated with ``@data``, this will effectively create as + many methods as data items are passed as parameters to ``@data``. + + The names of the test methods follow the pattern + ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the + data argument, starting with 1. + + For data we use a string representation of the data value converted into a + valid python identifier. If ``data.__name__`` exists, we use that instead. + + For each method decorated with ``@file_data('test_data.json')``, the + decorator will try to load the test_data.json file located relative + to the python file containing the method that is decorated. It will, + for each ``test_name`` key create as many methods in the list of values + from the ``data`` key. + + """ + for name, func in list(cls.__dict__.items()): + if hasattr(func, DATA_ATTR): + for i, v in enumerate(getattr(func, DATA_ATTR)): + test_name = mk_test_name(name, getattr(v, "__name__", v), i) + # 将用例描述信息改为用例数据的title字段 + # 原代码:test_data_docstring = _get_test_data_docstring(func, v) + test_data_docstring = v['title'] + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) + else: + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls diff --git a/python27Class/class03102020/demo2/readExcel.py b/python27Class/class03102020/demo2/readExcel.py new file mode 100644 index 0000000..49a6b19 --- /dev/null +++ b/python27Class/class03102020/demo2/readExcel.py @@ -0,0 +1,107 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/10 20:11 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl + +# 需求: 将excel中的数据读取出来,保存为以下格式 +""" +[ + {'title': '该账户已存在', 'expect_result': {"code": 0, "msg": "该账户已存在"}, 'data': ['python26', '123456', '123456']}, + {'title': '两次密码不一致', 'expect_result': {"code": 0, "msg": "两次密码不一致"}, 'data': ['python1', '12345655', '123456']}, + ] +""" + +# 封装的需求 +""" +1. 封装一个读数据的功能 + 读数据需要用到什么? excel文件路径, 表单名 + +2. 封装一个写入数据的方法: + 写数据需要用到哪些信息? 文件,表单,行,列,写入内容 +""" + + +class HandleExcel: + """ + 用来操作excel文件的类 + """ + + def __init__(self, filename, sheetname): + """ + 初始化对象属性 + :param filename: 文件名 + :param sheetname: 表单名 + """ + self.filename = filename + self.sheetname = sheetname + + def read_data(self): + """ + 读取excel文件中的数据 + :return: + """ + # 获取工作薄对象 + wb = openpyxl.load_workbook(self.filename) + # 选择表单 + sh = wb[self.sheetname] + # 按行获取所有数据,转换为列表 + rows_data = list(sh.rows) + + # 创建一个空列表,用来存放所有的用例数据 + case_data = [] + + # 获取表单中第一行数据(表头), 保存到title这个列表中 + title = [] + for i in rows_data[0]: + title.append(i.value) + + # 使用切片的方式,遍历除了第一行(表头)之外的行的数据 + for item in rows_data[1:]: + + # 每遍历出来一行数据就创建一个空列表来存放该行数据 + values = [] + # 遍历该行每个单元格的对象,获取单元格中的数据值存放到values列表中 + for i in item: + values.append(i.value) + # 每遍历完一行数据就拿该行的数据跟title表头打包转换为字典 + case = dict(zip(title, values)) + # 将该行用例数据追加到case_data列表中 + case_data.append(case) + # -------------------------------- + # 注意:从excel中读取出来的数据除了数值,其他的不管保存的是什么格式,读取出来的都是字符串。 + # 读取出来的数据可以在使用的时候使用eval来转换一下。 + + # 返回读取出来的所有数据 + return case_data + + def write_data(self, row, column, value): + """ + + :param row: 行 + :param column: 列 + :param value: 写入的值 + :return: + """ + # 获取工作簿对象 + wb = openpyxl.load_workbook(self.filename) + + # 选择表单 + sh = wb[self.sheetname] + + # 根据行列去写入内容 + sh.cell(row=row, column=column, value=value) + + # 把工作簿保存为文件 + wb.save(self.filename) + +if __name__ == '__main__': + excel = HandleExcel('cases.xlsx', 'register') + cases = excel.read_data() + print(cases) + + excel1 = HandleExcel('cases.xlsx', 'testsheet') + excel1.write_data(1, 2, 'test') diff --git a/python27Class/class03102020/demo2/registerPage.py b/python27Class/class03102020/demo2/registerPage.py new file mode 100644 index 0000000..02a9215 --- /dev/null +++ b/python27Class/class03102020/demo2/registerPage.py @@ -0,0 +1,68 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 8:59 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +users = [{'user': 'python26', 'password': '123456'}] + + +def register(username, password1, password2): + """ + + :param username: + :param password1: + :param password2: + :return: + """ + # 判断是否有参数为空 + if not all([username, password1, password2]): + return {"code": 0, "msg": "所有参数不能为空"} + # 注册功能 + for user in users: # 遍历出所有账号,判断账号是否存在 + if username == user['user']: + # 账号存在 + return {"code": 0, "msg": "该账户已存在"} + else: + if password1 != password2: + # 两次密码不一致 + return {"code": 0, "msg": "两次密码不一致"} + else: + # 账号不存在 密码不重复,判断账号密码长度是否在 6-18位之间 + if 6 <= len(username) >= 6 and 6 <= len(password1) <= 18: + # 注册账号 + users.append({'user': username, 'password': password2}) + return {"code": 1, "msg": "注册成功"} + else: + # 账号密码长度不对,注册失败 + return {"code": 0, "msg": "账号和密码必须在6-18位之间"} + + +if __name__ == "__main__": + res = register('python14', '123456', '123456') + print(res) + +""" +函数入参: +注意:参数传字符串类型,不需要考虑其他类型。 +参数1:账号 +参数2:密码1 +参数2:密码2 + + +函数内部处理的逻辑: + 判断是否有参数为空, + 判断账号密码是否在6-18位之间, + 判断账号是否被注册过, + 判断两个密码是否一致。 + 上面添加都校验通过才能注册成功,其他情况都注册失败, +各种情况的返回结果如下: + 注册成功 返回结果:{"code": 1, "msg": "注册成功"} + 有参数为空, 返回结果 {"code": 0, "msg": "所有参数不能为空"} + 两次密码不一致 返回结果:{"code": 0, "msg": "两次密码不一致"} + 账户已存在 返回结果:{"code": 0, "msg": "该账户已存在"} + 密码不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} + 账号不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} +""" \ No newline at end of file diff --git a/python27Class/class03102020/demo2/runTest.py b/python27Class/class03102020/demo2/runTest.py new file mode 100644 index 0000000..03c9686 --- /dev/null +++ b/python27Class/class03102020/demo2/runTest.py @@ -0,0 +1,38 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 9:33 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import os +import unittest + +from BeautifulReport import BeautifulReport + +from python27Class.class03072020.demo1.testRegister import RegisterTestCase + +""" +第一步:创建测试套件并加载测试用例 +""" +# 要执行的测试用例的位置 +path = os.path.dirname(os.path.abspath(__file__)) + +suite = unittest.defaultTestLoader.discover(path) + + +""" +第二步:执行测试套件中的用例, 使用BeautifulReport生成HTML测试报告 +2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" + + +# 测试报告存放的路径 +report_path = os.path.join(path, 'testReport') + +b_report = BeautifulReport(suite) +b_report.report('Register Function Report by flora', + 'register_beautiful_report.html', + report_dir=report_path + ) diff --git a/python27Class/class03102020/demo2/testRegister.py b/python27Class/class03102020/demo2/testRegister.py new file mode 100644 index 0000000..0169084 --- /dev/null +++ b/python27Class/class03102020/demo2/testRegister.py @@ -0,0 +1,43 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 9:47 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.class03102020.demo2.registerPage import register +from python27Class.class03102020.demo2.ddtNew import ddt, data +from python27Class.class03102020.demo2.readExcel import HandleExcel + +@ddt +class RegisterTestCase(unittest.TestCase): + excel = HandleExcel('cases.xlsx', 'register') + cases = excel.read_data() + + @data(*cases) + def test_register(self, case): + # 参数准备 + data = eval(case['data']) + # 预期结果准备 + expect_result = eval(case['expected']) + # 获取行号 + row = case['case_id'] + 1 + + # 获取实际结果 + actual_result = register(*data) + + try: + # 断言 + self.assertEqual(expect_result, actual_result) + except AssertionError as e: + # 断言不通过,引发断言异常 + # 往excel写入结果:未通过 + self.excel.write_data(row=row, column=5, value='未通过') + # 主动抛出异常(如果抛出异常,unittest会判断该用例是执行通过的。) + raise e + else: + # 断言通过,执行else + # 往excel写入结果:通过 + self.excel.write_data(row=row, column=5, value='通过') diff --git a/python27Class/class03102020/demo2/testReport/register_beautiful_report.html b/python27Class/class03102020/demo2/testReport/register_beautiful_report.html new file mode 100644 index 0000000..0018ea0 --- /dev/null +++ b/python27Class/class03102020/demo2/testReport/register_beautiful_report.html @@ -0,0 +1,7381 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/python/FloraHomeWork_0206.py b/python27Class/homeWork/python/FloraHomeWork_0206.py new file mode 100644 index 0000000..2fc8a3c --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0206.py @@ -0,0 +1,118 @@ +""" +================================= +Author: Flora Chen +2020/2/7 14:33 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、写一段代码,运行的时候在控制台依次提示提示输入姓名,年龄、性别, + + +最终在控制台按照以下格式输出:图片省略 +""" + + +name = input('请输入姓名:') +gender = input('请输入性别:') +age = input('请输入年龄:') +print('***************************') +print('姓名:', name) +print('性别:', gender) +print('年龄:', age) +print('***************************') + +""" +2、使用随机数模块生成一个5到10之间的浮点数,输出到控制台 +""" +import random +number = random.randint(5, 9) + random.random() +print('5到10之间的浮点数:', number) + + +""" +3、有5个数 a1=100,a2 =300,a3=400,b=180 、c=1000, + +要求一、请使用逻辑运算符和比较运算符去 比较c大于 a1、a2、a3是否全部成立。 + +要求二、请使用逻辑运算符和比较运算符去 比较b大于 a1、a2、a3至少1个成立。 +""" + +a1 = 100 +a2 = 300 +a3 = 400 +b = 180 +c = 1000 +print('比较c大于 a1、a2、a3是否全部成立', (c > a1) and (c > a2) and (c > a3)) +print('比较b大于 a1、a2、a3至少1个成立', (b > a1) or (b > a2) or (b > a3)) + +""" +4、运算符的应用: + + 1、计算 5的三次方,除以15的余数 + + 2、比较989除以57取余的结果,是否大于17 +""" + +result = (5 ** 3) % 15 +print('5的三次方,除以15的余数', result) + +result2 = 989 % 57 +print('比较989除以57取余的结果,是否大于17', result > 17) + +""" +5、总结上课笔记 +******Python中常见的数据类型****** +数值类型数据: +1. 整数(int),例如a = 100 +2. 小数(float)(浮点数), 例如 b = 2.3 +3. 布尔值(bool: True, False), 例如c= True, d = False + +内置函数type():可以用来查看数据的类型 + + +******Python中的运算符****** +1. 算术运算符: + - * / //(向下取整) %(取余) **(幂运算) +2. 比较运算符:== != > >= < <= 返回的是True或False +3. 赋值运算符:= += -= *= /= *= +示例: a += 1 相当于a = a + 1 +4. 逻辑运算符(用来比较2个条件):and(与) or(或) not(非) 返回的是True或False +and:所有条件都成立返回True,否则返回False。一假为假, 真真为真。 +or:只要有一个条件成立返回True,条件都不成立返回False。一真为真,假假为假。 +not: 取反。原来是True,返回False; 原来是False,返回True。 +5. 身份运算符(后面学) +6. 成员运算符(后面学) + + +******python中的内置随机函数random****** +random.random():随机生成一个0-1之间的浮点数;生成的小数范围是左闭右开,包含0,不包含1。 +random.randint():生成指定范围的整数;包含起始位置和终止位置的值。 + + +import random +number = random.random() +number1 = random.randint(0, 100) + +******字符串类型***** +1. 字符串可以通过单引号,双引号,三引号来表示。 +2. 单引号和双引号没有区别。 +3. 三引号可以用来表示多行字符串。 + + +******数据类型转换***** +整数和浮点数转换为字符串:使用str +字符串和浮点数转换为整数:使用int +整数和字符串转换为浮点数:使用float +整数和浮点数,字符串转换为布尔类型:bool; + +注意点: +使用字符串转换为int或float时,字符串的内容必须是数字(不能有字母和符号) +整数和浮点数转布尔值,只要不是0,返回的布尔值都是True,否则是False。 +字符串转布尔值,空字符串(引号中没有任何内容,包括空格或者其他标点符号)返回的布尔值是False,其他都是True。 + + + +扩展: +按编码规范格式化代码的快捷键(pycharm):Ctrl + Alt + L +""" \ No newline at end of file diff --git a/python27Class/homeWork/python/FloraHomeWork_0208.py b/python27Class/homeWork/python/FloraHomeWork_0208.py new file mode 100644 index 0000000..5caa82c --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0208.py @@ -0,0 +1,287 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/8 8:13 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、现在有变量 a = ‘hello’ , b = ‘python18’ c = ‘!’ ,通过相关操作转换成字符串:'hello python18 !'(注意点:转换之后单词之间有空格) +""" +a = 'hello' +b = 'python18' +c = '!' +# 方法一: +print(a, b, c) +# 方法二: +print(a + ' ' + b + ' ' + c) +# 方法三: +print(' '.join((a, b, c))) +# 方法四: +print('{} {} {}'.format(a, b, c)) +# 方法五: +print('%s %s %s' % (a, b, c)) +# 方法六: +# print(F'{a} {b} {c}') + +""" +2、使用random模块和字符串拼接的方法,随机生成一个130开头的手机号码(只能使用上课学过的知识去做)。 +""" +import random + +print('手机号码:130' + str(random.randint(1000000, 99999999))) + +# 木森老师代码 +#生成9位数 +n = random.randint(10000000, 999999999) +# 切片,取字符串的后8位 +n1 = str(n)[1:] +phone = '130' + n1 +print(phone) + +""" +3、有一个如下列表,请编写代码,提示用户输入1-7中的数字,分别代表周一到周日,根据用户输入,打印输出“今天是周X”(要求:使用上课学过的知识点来做) + +li = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] +""" +li = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] +number = int(input('请输入1-7中的数字,分别代表周一到周日:')) +print('今天是' + li[number - 1]) + +""" +4、现有字符串 str1 = "PHP is the best programming language in the world!" + 要求一:将给定字符串的PHP替换为Python + + 要求二:替换以后,将字符串以空格为分割点进行分割得到一个列表 +""" +str1 = "PHP is the best programming language in the world!" +# 要求一 +str2 = str1.replace('PHP', 'python') +print(str2) + +# 要求二 +li = str2.split(' ') +print(li) + +""" +5、切片操作 + 1、通过切片获取s = 'python java php' 中的java + + 2、通过切片获取 li = [2,3,1,4,6,2,5,6,7]中的 [2,5,6,7] +""" +s = 'python java php' +print(s[7:11]) +print(s[-8:-4]) + +li = [2, 3, 1, 4, 6, 2, 5, 6, 7] +print(str(li[5:])) +print(str(li[-4:])) + +""" +6、整理笔记 +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******字符串拼接****** +1. 通过+对字符串进行拼接 +示例: +str1 = 'python' +str2 = 'hello' +print(str1 + str2) # 输出结果:pythonhello +# 此种方法输出会在中间加空格 +print(str1, str2) # 输出结果:python hello + +2. 使用字符串的join方法进行拼接 +示例: +str1 = 'python' +str2 = 'hello' +j = '---' +str3 = j.join((str1, str2)) +print(str3) # 输出结果:python---hello + +或者 +str1 = 'python' +str2 = 'hello' +str3 = ' '.join((str1, str2)) +print(str3) # 输出结果:python hello + +或者 +str1 = 'python' +str2 = ' '.join(str1) +print(str2) # 输出结果:p y t h o n + +******字符串格式化输出****** +1. format格式化输出(常用方式,必须掌握) +示例: +str1 = '今天收到{}, 交来{}{}。开此收据为凭证。' +str2 = str1.format('flora', '学杂费', 666) +print(str2) # 输出结果: 今天收到flora, 交来学杂费666。开此收据为凭证。 +或: +print('今天收到{}, 交来{}{}。开此收据为凭证。'.format('flora', '学杂费', 666)) + +通过索引来控制填充的位置: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = input('请输入金额:') +print('今天收到{2}, 交来{1}费用{0}。开此收据为凭证。'.format(money, info, name)) + +保留指定小数位数: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = float(input('请输入金额:')) +print('今天收到{}, 交来{}费用${:.2f}。开此收据为凭证。'.format(name, info, money)) + +指定占位的字符串长度: +# 默认左对齐 +print('python:{:10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python:123 AAAAAAAAAAAAAAA + +# 左对齐 +print('python:{:<10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python:123 AAAAAAAAAAAAAAA + +# 右对齐 +print('python:{:>10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python: 123AAAAAAAAAAAAAAA + +# 居中对齐 +print('python:{:^10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:python: 123 AAAAAAAAAAAAAAA + +指定内容填充: +# 左对齐,以*填充 +print('python:{:*<10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:123*******AAAAAAAAAAAAAAA + +# 右对齐,以-填充 +print('python:{:->10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:-------123AAAAAAAAAAAAAAA + +# 居中对齐,以@填充 +print('python:{:@^10}AAAAAAAAAAAAAAA'.format('123')) +# 输出结果:@@@123@@@@AAAAAAAAAAAAAAA + +百分比显示效果: +print('百分比:{:.2%}'.format(0.89)) +# 输出结果:百分比:89.00% + +2. 传统的%格式化输出 +%s:万能占位符,可以接收任意类型的数据。 +%d:数值占位符,以整数的形式显示。 +%f: 数值占位符,以小数的形式显示。 + +示例: +print('今天收到%s, 交来%s%d。开此收据为凭证。' % ('flora', '学杂费', 666.98)) +# 输出结果: 今天收到flora, 交来学杂费666。开此收据为凭证。 + +print('今天收到%s, 交来%s%f。开此收据为凭证。' % ('flora', '学杂费', 666)) +# 输出结果: 今天收到flora, 交来学杂费666.000000。开此收据为凭证。 + +print('今天收到%s, 交来%s%.2f。开此收据为凭证。' % ('flora', '学杂费', 666.909090)) +# 输出结果:今天收到flora, 交来学杂费666.91。开此收据为凭证。 + +3. F表达式格式化输出 +示例: +name = input('请输入名字:') +info = input('请输入费用信息:') +money = input('请输入金额:') +print(F'今天收到{name}, 交来{info},{money}。开此收据为凭证。') + +******字符串转义****** +反斜杠\表示转义 +\t:制表符(tab键) +\n:换行符 +\\:表示1个反斜杠\ +示例: +print('python\thello') +# 输出结果:python hello + +print('python2\nhello2') +# 输出结果: +python2 +hello2 + +关闭字符串转义:r防转义 +print(r'python\thello') +# 输出结果:python\thello + +print(r'python2\nhello2') +# 输出结果:python2\nhello2 + +******字符串的常见操作方法****** +1. count查找字符串中某个字符串的个数 +示例: +print('123aa123bb123cc123dd'.count('123')) +# 输出结果:4 + +2. find查找字符串中某个字符串出现的第一个下标(索引)位置 +示例: +print('123aa123bb123cc123dd'.find('aa')) +# 输出结果:3 + +3. replace替换字符串中的某个字符串,默认替换所有 +示例: +print('123aa123bb123cc123dd'.replace('123', '*')) +# 输出结果:*aa*bb*cc*dd + +# 可控制替换的次数 +print('123aa123bb123cc123dd'.replace('123', '*', 1)) +# 输出结果:*aa123bb123cc123dd + +4. upper将字符串中的小写字母变成大写字母 +示例: +print('Hello World 132'.upper()) +# 输出结果:HELLO WORLD 132 + +5. lower将字符串中的大写字母变成小写字母 +示例: +print('Hello World 132'.lower()) +# 输出结果:hello world 132 + +6. split字符串分割 +示例: +# 以空格方式进行分割,返回的是个列表 +print('Hello World 132'.split(' ')) +# 输出结果:['Hello', 'World', '132'] +# 使用join方法反向操作 +print(' '.join(['Hello', 'World', '132'])) +# 输出结果:Hello World 132 + +******元组和列表****** +列表和元组中可以保存多个数据,可以是任意类型的,每个元素之间用逗号隔开。 +元组tuple: 用小括号来表示 +tup = ('python', 66, 88.88, True, [11, 22, 33]) + +列表list: 用中括号来表示 +li = ['python', 66, 88.88, True, [11, 22, 33]] + +扩展: +序列类型的数据:数据内部的元素是由顺序的(有下标) +序列类型的数据:字符串,列表,元组 +序列类型数据的共同特性: +1. 可以通过下标取值:通过下标获取数据内的元素 +示例: +# 正向取值:从前往后数下标,下标从0开始 +print('python'[2]) # 输出结果:t +print(['python', 66, 88.88, True, [11, 22, 33]][1]) # 输出结果:66 +print(('python', 66, 88.88, True, [11, 22, 33])[0]) # 输出结果:python + +# 反向取值:从后往前数下标,下标从-1开始 +print('python'[-2]) # 输出结果:o +print(['python', 66, 88.88, True, [11, 22, 33]][-1]) # 输出结果:[11, 22, 33] +print(('python', 66, 88.88, True, [11, 22, 33])[-3]) # 输出结果:88.88 + +2. 可以通过切片操作:获取数据中某一段数据,[起始位置:终止位置], 左闭右开 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print('[起始位置:终止位置], 左闭右开:', li[0:3]) +# 输出结果:[起始位置:终止位置], 左闭右开: ['python', 66, 88.88] + + + + +""" diff --git a/python27Class/homeWork/python/FloraHomeWork_0211.py b/python27Class/homeWork/python/FloraHomeWork_0211.py new file mode 100644 index 0000000..a4489e1 --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0211.py @@ -0,0 +1,288 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/12 09:57 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +""" +一、现在有一个列表 li2=[1,2,3,4,5], + + 第一步:请通过三行代码将上面的列表,改成这个样子 li2 = [0,1,2,3,66,5,11,22,33], + 第二步:对列表进行升序排序 (从小到大) + 第三步:将列表复制一份进行降序排序(从大到小) +""" +li2 = [1, 2, 3, 4, 5] +# 第一步 +li2.extend([11, 22, 33]) +li2.insert(0, 0) +li2[4] = 66 +print('第一步:', li2) +# 第二步 +li2.sort() +print('第二步:', li2) +# 第三步 +li3 = li2.copy() +li3.sort(reverse=True) +print('第三步:', li2) +# 第三步或者可以这样 +li3 = li2.copy() +li2.sort() +li2.reverse() +print('第三步:', li2) + +""" +二、定义一个空列表user=[], 分别提示用户输入,姓名,年龄,身高,用户输入完之后,将输入的信息作为添加的列表中保存,然后按照以下格式输出: + 用户的姓名为:xxx,年龄为:xxx, 身高为:xxx ,请仔细核对 +""" +user = [] +name = input('请输入姓名:') +age = input('请输入年龄:') +height = float(input('请输入身高:')) +user.extend([name, age, height]) +print('用户的姓名为:{},年龄为:{}, 身高为:{:.2f} ,请仔细核对'.format(name, age, height)) + +""" +三、切片练习 + +1、现在有一个字符串 s = 'abcdefghijk', + + 要求一:通过切片获取: defg + + 要求二:通过切片获取:cgk + + 要求三:通过切片获取:jhf +""" + +s = 'abcdefghijk' +# 要求一 +print('通过切片获取: defg --', s[3:7]) +print('通过切片获取: defg --', s[-8:-4]) +# 要求二 +print('通过切片获取: cgk --', s[2::4]) +# 要求三 +print('通过切片获取: jhf --', s[-2:-7:-2]) + + +""" +2、现在有一个列表li = [1,2,3,4,5,6,7,8,9] 请通过切片得出结果 [3,6,9] +""" +li = [1, 2, 3, 4, 5, 6, 7, 8, 9] +print('通过切片得出结果 [3,6,9] --', li[2::3]) + + +""" +四、整理笔记 +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******列表切片****** +可以通过切片操作:获取数据中某一段数据 +用法一: [起始位置:终止位置], 左闭右开 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print('[起始位置:终止位置], 左闭右开:', li[0:3]) +# 输出结果:[起始位置:终止位置], 左闭右开: ['python', 66, 88.88] + +# 使用反向的下标进行切片 +print(li[-2:-1]) # 输出结果:[True] + +# 正向和反向下标可以混用 +print(li[1:-2]) # 输出结果:[66, 88.88] + +用法二:[起始位置:终止位置:步长] +1. 步长为正数 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +# 默认步长为1,默认打印整个列表 +print(li[::]) # 输出结果: ['python', 66, 88.88, True, [11, 22, 33]] +# 步长为2, 2个元素中取第一个元素。所以是1 3 5 +print(li[::2]) # 输出结果: ['python', 88.88, [11, 22, 33]] +# 步长为3, 3个元素中取第一个元素。所以是1 4 +print(li[::3]) # 输出结果: ['python', True] +# 步长为4, 4个元素中取第一个元素。所以是1 5 +print(li[::4]) # 输出结果: ['python', [11, 22, 33]] + +2. 步长设置为负数 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +# 步长为-1, 是从后往前切片 +print(li[::-1]) # 输出结果:[[11, 22, 33], True, 88.88, 66, 'python'] +print(li[-1:-4:-1]) # 输出结果:[[11, 22, 33], True, 88.88] + +******列表的常见操作方法****** +列表list: 用中括号[]来表示 +列表可以保存多个数据,可以是任意类型的,每个元素之间用逗号隔开。 +列表可以转换成布尔值,空列表(li = [])的布尔值为False,其他的布尔值都是True。 + +1. 内置函数len:获取(字符串,列表,元组,字典,集合)的长度 +示例: +li = ['python', 66, 88.88, True, [11, 22, 33]] +print(len(li)) # 输出结果:5 + +2. 新增列表元素 +append(): 在列表尾部追加元素 +示例: +li = ['nancy', 'lily'] +li.append('flora') +print(li) # 输出结果:['nancy', 'lily', 'flora'] + +insert(需要添加元素的下标位置, 需要添加的元素):指定位置添加元素 +示例: +li = ['nancy', 'lily', 'flora'] +li.insert(1, 'robot') +print(li) # 输出结果:['nancy', 'robot', 'lily', 'flora'] + +extend():一次性在列表尾部添加多个元素。注意:必须将需要添加的多个元素放在列表或者元组里面。 +示例: +li = ['nancy', 'lily', 'flora'] +li.extend(['jane', 'robot', 1, 2]) +print(li) # 输出结果:['nancy', 'lily', 'flora', 'jane', 'robot', 1, 2] + +3. 删除列表元素 +remove(元素值):删除列表指定的元素 +示例: +li = ['nancy', 'lily', 'flora'] +li.remove('lily') +print(li) # 输出结果:['nancy', 'flora'] + +pop():通过下标删除指定的元素,默认删除最后一个 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +li.pop() +print(li) # 输出结果:['nancy', 'lily', 'flora', 'robot'] +li.pop(1) +print(li) # 输出结果:['nancy', 'flora', 'robot'] + +clear():清空列表(删除列表中的所有元素) +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +li.clear() +print(li) # 输出结果:[] + +4. 查看列表元素 +通过下标取值 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane'] +# 通过下标取值查找元素 +print(li[1]) # 输出结果:lily + +index():查找元素的下标值(找到第一个就返回,不会继续再查找;如果元素不存在会报错。) +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +index = li.index('flora') +print(index) # 输出结果:2 + +# 在指定范围内查找元素的下标值,左闭右开 +index = li.index('flora', 3, 6) +print(index) # 输出结果:5 + +count():查找列表中某个元素的个数 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +print(li.count('flora')) # 输出结果:2 + +5. 修改列表元素 +通过下标赋值 +示例: +li = ['nancy', 'lily', 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] +li[1] = 11 +print(li) # 输出结果:['nancy', 11, 'flora', 'robot', 'jane', 'flora', 'miya', 'apple'] + +6. 列表的其他方法 +sort():对列表进行排序(列表中全是数值类型);如果列表中全是字符串是按照ASCII值进行排序的。 +示例: +li = [11, 2, 353, 44, 88, 99, 123] +li.sort() # 默认从小到大排序, reverse默认为False +print(li) # 输出结果:[2, 11, 44, 88, 99, 123, 353] +li.sort(reverse=True) # 从大到小排序 +print(li) # 输出结果:[353, 123, 99, 88, 44, 11, 2] + +reverse():将列表反向,从末尾到起始排序 +示例: +li = [11, 2, 353, 44, 88, 99, 123] +li.reverse() # 此操作相当于 li[::-1] +print(li) # 输出结果:[123, 99, 88, 44, 353, 2, 11] + +copy():复制 +示例: +li = [1, 2, 3, 4, 5, 6, 7] +# 变量赋值,引用的是li中的数据 +li2 = li +print(id(li)) # 输出结果:2144668143360 +print(id(li2)) # 输出结果:2144668143360 +# 在列表类li2中追加元素,同样会作用到li中 +li2.append(9) +print(li) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] +print(li2) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] + +# 复制 +li3 = li.copy() +print(id(li3)) # 输出结果:2814574980480 +print(li is li3) # 输出结果:False +# 在列表类li3中追加元素,不会影响li +li3.append(80) +print(li) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9] +print(li3) # 输出结果:[1, 2, 3, 4, 5, 6, 7, 9, 80] + +******运算符补充****** +身份运算符(is, is not):比较2个数据是否引用的是同一个对象(比较id内存地址是否一致) +示例: +li = [11, 2, 353, 44] +li2 = [11, 2, 353, 44] +li3 = li +# 内置函数id:查看数据的内存地址 +print(id(li)) # 输出结果:1792807521984 +print(id(li2)) # 输出结果:1792807540928 +print(id(li3)) # 输出结果:1792807521984 +print(li is li2) # 输出结果:False +print(li is li3) # 输出结果:True +print(li is not li3) # 输出结果:False + +扩展: +在python中 -5 到 256 之间的数据(小整数池),内存地址都是一样的。 +# 在终端运行 +a = -5 +b = -5 +print(id(a)) # 输出结果:140706950989280 +print(id(b)) # 输出结果:140706950989280 + +a = -6 +b = -6 +print(id(a)) # 输出结果:1739394026288 +print(id(b)) # 输出结果:1739394026352 + +成员运算符(in, not in):判断某个元素是否存在于列表中 +示例: +li = [1, 2, 3, 4, 5, 6, 7] +zs = 1 +ls = 8 +# 判断zs, ls是否存在于列表中 +print(zs in li) # 输出结果:True +print(ls in li) # 输出结果:False + +# 判断zs, ls是否不存在于列表中 +print(zs not in li) # 输出结果:False +print(ls not in li) # 输出结果:True + + +******元组****** +元组tuple: 用小括号来表示 +元组的方法只有查询的方法。没有添加元素,修改元素,删除元素的方法。 +1. 通过下标取值 +index():查找元素的下标值(找到第一个就返回,不会继续再查找;如果元素不存在会报错。) +示例: +tup = (1, 2, 33, 4, 5, 6, 33, 44, 33, 7) +print(tup[2]) # 输出结果:33 +print(tup.index(33)) # 输出结果:2 +print(tup.index(33, 3, 8)) # 输出结果:6 + +2. count():查找列表中某个元素的个数 +示例: +tup = (1, 2, 33, 4, 5, 6, 33, 44, 33, 7) +print(tup.count(33)) # 输出结果:3 + +""" diff --git a/python27Class/homeWork/python/FloraHomeWork_0213.py b/python27Class/homeWork/python/FloraHomeWork_0213.py new file mode 100644 index 0000000..b01f5a1 --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0213.py @@ -0,0 +1,191 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/13 19:49 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、 将字符串中的单词位置反转,“hello xiao mi” 转换为 “mi xiao hello” +(提示:通过字符串分割,拼接,列表反序等知识点来实现) +""" +str1 = 'hello xiao mi' +str_list = str1.split(' ') +str_list.reverse() +# 如果是直接打印 这样就可以了 +print('{} {} {}'.format(str_list[0], str_list[1], str_list[2])) +# 但是如果要变成一个新的变量,增加如下操作 +new_str = ' '.join(str_list) +# new_str = ' '.join((str_list[0], str_list[1], str_list[2])) +print(new_str) +new_str2 = '{} {} {}'.format(str_list[0], str_list[1], str_list[2]) +print(new_str2 ) + +""" +2、字典的增删查改操作: 某比赛需要获取你的个人信息,编写一段代码要求如下: + 1、运行时分别提醒输入 姓名、性别、年龄 ,输入完了,请将数据通过字典存储起来, + 2、数据存储完了,然后输出个人介绍,格式如下: 我的名字XXX,今年XXX岁,性别XX,喜欢敲代码 + 3、有一个人对你很感兴趣,平台需要您补足您的身高和联系方式; + 4、平台为了保护你的隐私,需要你删除你的联系方式; + 5、你为了取得更好的成绩, 你添加了一项自己的擅长技能。 +""" +# 1 +name = input('请输入您的姓名:') +gender = input('请输入您的性别:') +age = input('请输入您的年龄:') +info = {'name': name, 'gender': gender, 'age': int(age)} +# 2 +print('我的名字{},今年{}岁,性别{},喜欢敲代码'.format(info['name'], info['age'], info['gender'])) +# 3 +height = input('请输入您的身高:') +phone = input('请输入您的联系方式:') +info.update({'height': float(height), 'phone': phone}) +print('我的名字{},今年{}岁,性别{},身高{:.2f},联系方式{},喜欢敲代码;'.format(info['name'], info['age'], info['gender'], info['height'], info['phone'])) +# 4 +info.pop('phone') +print('我的名字{},今年{}岁,性别{},身高{:.2f},喜欢敲代码;'.format(info['name'], info['age'], info['gender'], info['身高'])) +# 5 +skill = input('请输入您擅长的技能:') +info['skill'] = skill +print('我的名字{},今年{}岁,性别{},身高{:.2f},擅长{},喜欢敲代码;'.format(info['name'], info['age'], info['gender'], info['height'], info['skill'])) + +""" +3、利用下划线将列表li=[“python”,“java”,“php”]的元素拼接成一个字符串,然后将所有字母转换为大写, +""" +li = ['python', 'java', 'php'] +# 方法一 +str_li = li[0] + '_'+ li[1] + '_' + li[2] +# 方法二 +str_li2 = '_'.join(li) +# str_li2 = '_'.join((li[0], li[1], li[2])) +print('方法一:', str_li.upper()) +print('方法二:', str_li2.upper()) + +""" +4、利用切片把 'http://www.python.org'中的python字符串取出来 +""" +url = 'http://www.python.org' +# 方法一 +print(url[11:17]) +# 方法二 +print(url[-10:-4]) + +""" +5、编写一个买橘子的计算器: + 运行代码提示输入橘子的价格(要考虑小数的情况), + 然后随机生成斤数(1-100之间整数),最后计算应付金额,控制台输出如下信息(所有数据输出时都要保留两位小数) + 输出内容格式:“您购买的橘子为xx.xx斤,每斤xx.xx元,应支付金额为xx.xx” +""" +import random +orange_price = float(input('请输入橘子的价格:')) +weight = random.randint(1, 100) +total_price = orange_price * weight +print('您购买的橘子为{:.2f}斤,每斤{:.2f}元,应支付金额为{:.2f}'.format(weight, orange_price, total_price)) + +""" +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******字典dict****** +1. 字典的定义 +花括号{}表示字典,字典中的元素是由键值(key:value)对组成的,每个元素用逗号隔开。 +字典是没有下标索引的,其键key就是索引。 +示例: +dic = {} +dict2 = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(type(dic)) # 输出结果: +print(dict2) # 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dict2['name']) # 输出结果:flora + +2. 字典中的相关规范 +字典中的键不能重复。 +字典中的键只能使用不可变类型(字符串,数值类型,元组)的数据(通常是用字符串)。 +字典中的值可以是任何数据类型。 + +扩展: +不可变类型的数据:数值类型,字符串,元组 +可变类型的数据:列表,字典,集合 + +3. 字典的相关操作 +添加一个元素 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic['height'] = 156 +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200', 'height': 156} + +添加多个元素 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic.update({'height': 156, 'heavy': '56kg'}) +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '10220020200', 'height': 156, 'heavy': '56kg'} + +修改元素:键已存在就是修改。否则是新增。 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +dic['phone'] = '18956423668' +print(dic) +# 输出结果:{'name': 'flora', 'age': 18, 'phone': '18956423668'} + +删除元素 +pop():通过键去删除指定的键值对,返回键对应的值 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.pop('phone') +print(res) # 输出结果:10220020200 +print(dic) +# 输出结果:{'name': 'flora', 'age': 18} + +popitem():删除最后添加进去的键值对,以元组的形式返回一个键值对 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.popitem() +print(res) # 输出结果:('phone', '10220020200') +print(dic) +# 输出结果:{'name': 'flora', 'age': 18} + + +查找元素 +通过键进行索引取值,键不存在会报错 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic['phone'] +print(res) # 输出结果:10220020200 + +get():通过键获取对应的值,键不存在不会报错,但是会返回None +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +res = dic.get('phone') +print(res) # 输出结果:10220020200 +res2 = dic.get('heg') #键不存在 +print(res2) # 输出结果:None + +获取字典中的所有键,所有值,所有键值对 +keys():获取字典中所有的键 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.keys()) # 输出结果:dict_keys(['name', 'age', 'phone']) +print(list(dic.keys())) # 可通过list()转换成列表 +# 输出结果:['name', 'age', 'phone'] + +values():获取字典中所有的值 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.values()) # 输出结果:dict_values(['flora', 18, '10220020200']) +print(list(dic.values())) # 可通过list()转换成列表 +# 输出结果:['flora', 18, '10220020200'] + +items():获取字典中所有的键值对 +示例: +dic = {'name': 'flora', 'age': 18, 'phone': '10220020200'} +print(dic.items()) # 输出结果:dict_items([('name', 'flora'), ('age', 18), ('phone', '10220020200')]) +print(list(dic.items())) # 可通过list()转换成列表 +# 输出结果:[('name', 'flora'), ('age', 18), ('phone', '10220020200')] + + +""" \ No newline at end of file diff --git a/python27Class/homeWork/python/FloraHomeWork_0215.py b/python27Class/homeWork/python/FloraHomeWork_0215.py new file mode 100644 index 0000000..f1ffa76 --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0215.py @@ -0,0 +1,362 @@ +""" +====================================== +Author: Flora.Chen +Time: 2020/2/15 13:03 +~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ ~ _ ~ +====================================== +""" + +""" +一、请获取下面数据中的token,和reg_name +data = { + "code": 0, + "msg": "OK", + "data": { + "id": 74711, + "leave_amount": 29600.0, + "mobile_phone": "13367899876", + "reg_name": "小柠檬666", + "reg_time": "2019-12-13 11:12:53.0", + "type": 0, + "token_info": { + "token_type": "Bearer", + "expires_in": "2019-12-30 22:28:57", + "token": "eyJhbGciOiJIUzUxMiJ9.eyJtZW1iZXJfaWQiOjc0NzExLCJleHAiOjE1Nzc3MTYxMzd9.eNMtnEWr57iJoZRf2IRsGDWm2GKj9LZc1J2SGRprAwOk7EPoJeXSjJwdh0pcVVJygHmsbh1TashWqFv1bvCVZQ" + } + }, + "copyright": "Copyright 柠檬班 © 2017-2019 湖南省零檬信息技术有限公司 All Rights Reserved" +} +""" +data = { + "code": 0, + "msg": "OK", + "data": { + "id": 74711, + "leave_amount": 29600.0, + "mobile_phone": "13367899876", + "reg_name": "小柠檬666", + "reg_time": "2019-12-13 11:12:53.0", + "type": 0, + "token_info": { + "token_type": "Bearer", + "expires_in": "2019-12-30 22:28:57", + "token": "eyJhbGciOiJIUzUxMiJ9.eyJtZW1iZXJfaWQiOjc0NzExLCJleHAiOjE1Nzc3MTYxMzd9.eNMtnEWr57iJoZRf2IRsGDWm2GKj9LZc1J2SGRprAwOk7EPoJeXSjJwdh0pcVVJygHmsbh1TashWqFv1bvCVZQ" + } + }, + "copyright": "Copyright 柠檬班 © 2017-2019 湖南省零檬信息技术有限公司 All Rights Reserved" +} +token = data['data']['token_info']['token'] +reg_name = data['data']['reg_name'] +print(token) +print(reg_name) + +""" +二、有下面几个数据 ,t1 = ("aa",11) t2= (''bb'',22) li1 = [("cc",22)] +请通过学过的知识点,进行相关操作变为如下字典: {"aa":11,"cc":22,"bb":22} +""" +t1 = ('aa', 11) +t2 = ('bb', 22) +li1 = [('cc', 22)] +# 先将元祖t1, t2添加到列表li1中 +li1.insert(0, t1) +li1.append(t2) +# 再将列表转换成字典 +dic1 = dict(li1) +# 打印字典 +print(dic1) + +""" +三、当前有一个列表 li = [11,22,33,22,22,44,55,77,88,99,11], + 要求一:去除列表中的重复元素, + 要求二:去重后删除 77,88,99这三个元素 +""" +li = [11, 22, 33, 22, 22, 44, 55, 77, 88, 99, 11] +# 要求一:去除列表中的重复元素 +set1 = set(li) +print(set1) +# 要求二:去重后删除 77,88,99这三个元素 +new_li = list(set1) +new_li.remove(77) +new_li.remove(88) +new_li.remove(99) +print(new_li) + +""" +四、利用random函数生成随机整数(范围1-9),然后用户输入一个数字,来进行比较: +如果大于随机数,则打印印大于随机数。 +如果小于随机数,则打印小于随机数。 +如果相等随机数,则打印等于随机数。 +""" +import random + +random_number = random.randint(1, 9) +input_number = int(input('请输入一个数字:')) +if input_number > random_number: + print('大于随机数') +elif input_number < random_number: + print('小于随机数') +else: + print('等于随机数') + +""" +五、一家商场在降价促销。如果购买金额50-100元(包含50元和100元)之间,会给打九折, +如果购买金额大于100元会给打八折。编写一程序,询问购买价格,再打印出折扣和最终价格。 +""" +price = float(input('请输入你购买的价格:')) +price = int(price) +if price <= 0: + print('输入有误!') +elif 0 < price < 50: + cost = int(price * 0.9) + print('商品打9折,最终价格为{}'.format(cost)) +elif 50 <= price <= 100: + print('商品不打折!') +else: + cost = int(price * 0.8) + print('商品打8折,最终价格为{}'.format(cost)) + +""" +六、提示用户输入一个数(只考虑整数),判断这个数能同时被3和5整除, +能整除打印 :这个数据我喜欢 +不能整除打印:这个数据不太喜欢 +""" +number = int(input('请输入与一个数:')) +if (number % 5 == 0) and (number % 3 == 0): + print('这个数据我喜欢') +else: + print('这个数据不太喜欢') + +""" +七、整理笔记 +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******集合****** +1. 集合的定义 +集合: set类型, 通过{}来表示 +内部的数据{value, value1, value2} +示例: +set1 = {11, 22, 33, 44, 55} +print(type(set1)) # 输出结果: + +2. 集合的特性 +集合的数据不能存在重复的元素; +集合中的数据只能是不可变类型(数值类型,字符串,元组); +集合和字典都是无序的,没有下标索引; +集合是可变类型的数据。 +集合的操作: + add: 添加数据 + pop:删除数据 +示例: +set1 = {11, 22, 33, 44, 55, 55} +print(set1) # 输出结果:{33, 11, 44, 22, 55} +set1.add(678) +print(set1) # 输出结果:{33, 678, 11, 44, 22, 55} +set1.pop() # 随机删除一个元素 +print(set1) # 输出结果:{678, 11, 44, 22, 55} + +3. 集合的应用 +对数据的去重 +示例: +# 对字符串去重 +str1 = 'dfgdfghjkhjk' +s1 =set(str1) +print(s1) # 输出结果:{'d', 'k', 'f', 'j', 'g', 'h'} +# 对列表去重 +li = [11, 11, 22, 22, 33] +s1 =set(li) +print(list(s1)) # 输出结果:[33, 11, 22] + +用来区分数据是否可变 +# 运行不报错的就都是不可变类型的:数值类型,字符串,元组 +set1 = {111, 12.33, '243', True, (1, 2)} + +# 运行报错的就都是可变类型的:列表,字典,集合 +# set2 = {[1, 2, 3]} # TypeError: unhashable type: 'list' +# set3 = {{'name': 'flora'}} # TypeError: unhashable type: 'dict' +set4 = {{1,2,3}} # TypeError: unhashable type: 'set' + + +******数据类型总结****** +1. 按数据结构分类 +数值类型:整数,浮点数,布尔值 +序列类型:字符串,列表,元组(可以通过下标取值,支持切片操作) +散列类型:字典,集合(元素内部是无序的,没有下标) + +2. 数据类型的可变与不可变 +不可变类型:数值类型,字符串,元组 + 字符串和元组定义之后不能修改内部结构或者值(内存单元中的值),为不可变类型 +可变类型:列表,字典,集合 +如何区分可变不可变数据:定义一个集合,把数据放到集合中看会不会报错。会报错的是可变类型。 + +******控制流****** +顺序:代码从上往下执行 +分支:根据不同的条件,执行不同的代码 +循环:特定的代码重复执行 +注意:python中通过缩进来区分代码块的。 + +******条件判断****** +1. if语句 +if 条件: + # 条件成立执行的代码块 + +示例: +# 用户输入考试成绩,请判断是否及格。 +score = float(input('请输入您的成绩:')) +if score >= 60: + # 条件成立执行的代码块 + print('考试及格!') + + +2. if - else语句 +if 条件: + # 条件成立执行的代码块 +else: + # 条件不成立执行的代码块 + +示例: +# 用户输入考试成绩,请判断是否及格。如果考试不及格,打印:考试不及格,晚上通宵敲代码! +score = float(input('请输入您的成绩:')) +if score >= 60: + # 条件成立执行的代码块 + print('考试及格!') +else: + # 条件不成立执行的代码块 + print('考试不及格,晚上通宵敲代码!') + +3. if - elif - else语句 +if 条件1: + # 条件成立执行的代码块 +elif 条件2: + # 条件2成立执行的代码块 +elif 条件3: + # 条件3成立执行的代码块 +else: + # 以上条件均不成立执行的代码块 + +# 用户输入考试成绩,根据不同等级进行区分(A: 90分以上, B:80-90分, C: 60-80分, D:60分以下) +score = int(input('请输入您的成绩:')) +if 0 <= score < 60: + print('您的成绩为D!') +elif 60 <= score < 80: + print('您的成绩为C!') +elif 80 <= score < 90: + print('您的成绩为B!') +elif 90 <= score < 100: + print('您的成绩为A!') +else: + print('您输入的成绩有误!') + + +4. 多个条件同时判断 +# 登录小案例:事先存储一组账号密码,提示用户输入账号和密码,然后判断账号密码是否输入正确 +user_info = {'user': 'flora', 'pwd': '123455555Az'} + +username = input('请输入账号:') +passwd = input('请输入密码:') + +# 方式一:使用嵌套方式 +if username == user_info['user']: + if passwd == user_info['pwd']: + print('账号密码输入正确!') + else: + print('密码输入不正确!') +else: + print('账号输入不正确!') + +# 方式二:使用逻辑运算符去判断多个条件 +if username == user_info['user'] and passwd == user_info['pwd']: + print('账号密码输入正确!登录成功!') +else: + print('账号或密码输入不正确!登录失败!') + +总结: +使用if开启一个条件判断语句: + 一个条件语句中只有一个if,但是一个条件语句中可以有多个或者一个或者零个elif; + 一个条件语句中只有一个或者零个else。 +if判断成立的标准: + if成立的标准是根据if后面的python表达式或者数据的布尔值是否为True来确定条件是否成立 + +******python中数据的布尔值****** +非0位True:None, 数字0或者数据长度为0(len())的布尔值为False, 其他数据布尔值都是True; +数据长度为0, 例如:空字符串,空列表,空元祖,空字典 + +示例: +str1 = 'python' +li = [1, 2, 2] +if li: + print('成立!') +else: + print('不成立!') + +******while循环(条件循环)****** +1. while循环的使用 +如果条件一直成立,则一直循环做条件满足的事情,直到条件不成立,结束循环。 +while 条件: + # 条件成立,循环执行的代码块 + # 条件成立,循环执行的代码块 + # 条件成立,循环执行的代码块 + # ...... + +示例: +# 创建一个变量来保存循环的次数 +i = 0 +while i < 5: + print('hello python') + i += 1 # i = i + 1 +# 输出结果: +# hello python +# hello python +# hello python +# hello python +# hello python + +2. 死循环以及相关案例的使用 +死循环:循环的条件一直成立,在循环体中无限循环,称之为死循环。 +避免写代码的过程中因为逻辑问题,造成代码死循环。 +示例: +while True: + print('hello python') + +3. break强制跳出循环 +死循环在特定的需求下,我们也会使用,再循环内部要实现跳出循环的机制(合理使用break)。 +示例: +while True: + user_info = {'user': 'flora', 'pwd': '123455555Az'} + username = input('请输入账号:') + passwd = input('请输入密码:') + + if username == user_info['user'] and passwd == user_info['pwd']: + print('账号密码输入正确!登录成功!') + break + else: + print('账号或密码输入不正确!请重新输入!') + +4. 循环内嵌套条件语句 +示例: +# 打印3次之后强制退出循环 +i = 0 +while i < 5: + print('hello python') + i += 1 # i = i + 1 + # 当i=3时,退出循环 + if i == 3: + break + +5. continue终止本轮循环,直接进行下次循环的条件判断 +示例: +# 第5-7次不打印 +i = 0 +while i < 10: + i += 1 # i = i + 1 + # 当i在5~7之间,则执行continue终止本轮循环,进行下轮循环的条件判断 + if 5 <= i <= 7: + continue + print('hello python') + + + +""" diff --git a/python27Class/homeWork/python/FloraHomeWork_0218.py b/python27Class/homeWork/python/FloraHomeWork_0218.py new file mode 100644 index 0000000..d49775c --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0218.py @@ -0,0 +1,331 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/18 19:45 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、一、输出99乘法表,结果如下:(提示嵌套for循环,参照上课打印三角形的案例) +""" +for i in range(1, 10): + for j in range(1, i + 1): + print('{} * {} = {}\t'.format(i, j, i * j), end='') + print() + +""" +2、实现剪刀石头布游戏(),提示用户输入要出的拳 :石头(1)/剪刀(2)/布(3)/退出(4) 电脑随机出拳比较胜负,显示 用户胜、负还是平局。 + +运行如下图所示(提示:while循环加条件判断,做判断时建议先分析胜负的情况): +""" + +# musen老师代码 +import random + +print('---石头剪刀布游戏开始---') +print('请按照下面的提示出拳:') +li = ['石头', '剪刀', '布'] +while True: + print('石头【1】/剪刀【2】/布【3】/结束游戏【4】') + user_num = int(input('请输入你的选项:')) + r_num = random.randint(1, 3) + print(r_num) + if 1 <= user_num <= 3: + if r_num == user_num: + print('您的出拳为:{}, 电脑出拳:{},平局'.format(li[user_num - 1], li[r_num - 1])) + elif (user_num - r_num) == -1 or (user_num - r_num) == 2: + print('您的出拳为:{}, 电脑出拳:{},您胜利了'.format(li[user_num - 1], li[r_num - 1])) + else: + print('您的出拳为:{}, 电脑出拳:{},您输了'.format(li[user_num - 1], li[r_num - 1])) + elif user_num == 4: + print('游戏结束!') + break + else: + print('您出拳有误,请按规矩出拳!') +# -------------------------------------------------------------------------- +while True: + print('---石头剪刀布游戏开始---') + print('请按照下面的提示出拳:\n石头【1】/剪刀【2】/布【3】/结束游戏【4】') + user_hand = int(input('请输入你的选项:')) + # 根据用户输入的数字,输出用户出拳的象征 + if user_hand == 1: + user_icon = '石头' + print('用户出的是:', user_icon) + elif user_hand == 2: + user_icon = '剪刀' + print('用户出的是:', user_icon) + elif user_hand == 3: + user_icon = '布' + print('用户出的是:', user_icon) + elif user_hand == 4: + print('游戏结束!') + break + else: + print('您出拳有误,请按规矩出拳!') + # 根据系统随机输出的数字,输出系统出拳的象征 + system_hand = random.randint(1, 3) + if system_hand == 1: + system_icon = '石头' + print('系统出的是:', system_icon) + elif system_hand == 2: + system_icon = '剪刀' + print('系统出的是:', system_icon) + elif system_hand == 3: + system_icon = '布' + print('系统出的是:', system_icon) + # 根据用户以及系统的出拳,决定胜负 + if ((user_hand == 1) and (system_hand == 2)) or ((user_hand == 2) and (system_hand == 3)) or ( + (user_hand == 3) and (system_hand == 1)): + print('您的出拳为:{}, 电脑出拳:{},您胜利了\n'.format(user_icon, system_icon)) + elif user_hand == system_hand: + print('您的出拳为:{}, 电脑出拳:{},平局\n'.format(user_icon, system_icon)) + + else: + print('您的出拳为:{}, 电脑出拳:{},您输了\n'.format(user_icon, system_icon)) + + + +""" +3、通过定义一个计算器函数,调用函数分别提示用户输入数字1,数字2,然后再提示用户选择 : 加【1】 减【2】 乘【3】 除【4】, + + +根据不同的选择完成不同的计算 ,然后打印结果(提示:函数中加条件判断)。 +""" + + +def calculate(): + print('欢迎使用计算器!') + num1 = int(input('请输入数字1:')) + num2 = int(input('请输入数字2:')) + cal_way = int(input('请选择计算方式(加【1】 减【2】 乘【3】 除【4】):')) + if cal_way == 1: + return num1 + num2 + elif cal_way == 2: + return num1 - num2 + elif cal_way == 3: + return num1 * num2 + elif cal_way == 4: + return num1 / num2 + else: + return print('您的输入有误') + + +print('结果是:', calculate()) + +""" +5、扩展练习题:不用提交,不计入评分(有时间的同学可以做): + + + 学习控制流程时,我们讲了一个登录的案例,现在要求大家通过代码实现一个注册的流程,基本要求: + +1、运行程序,提示用户,输入用户名,输入密码,再次确认密码。 +​ +2、判读用户名有没有被注册过,如果用户名被注册过了,那么打印结果该用户名已经被注册。 +​ +3、用户名没有被注册过,则判断两次输入的密码是否一致,一致的话则注册成功,否则给出对应的提示。 +​ +4、下面是已注册的两个账户,注册成功的账号密码按下面的形式保存到列表users中 +users = [{"uaer":"py27","pwd":"lemonban"},{"uaer":"py28","pwd":"lemonban2"}] +​ +提示:要是有for-else语句才能实现 +""" +# 运行程序,提示用户,输入用户名,输入密码,再次确认密码 +username = input('请输入用户名:') +passwd = input('请输入密码:') +passwd_confirm = input('请再次输入密码:') + +# 已有的用户列表 +users = [{'user': 'py27', 'pwd': 'lemonban'}, {'user': 'py28', 'pwd': 'lemonban2'}] + +# 循环遍历用户列表 +for items in users: + # 判断用户名是否已注册,已注册就提示用户已注册,并且终止循环 + if username == items['user']: + print('该用户名已经被注册:', username) + break +# 用户名未注册,就判断用户两次输入的密码是否一致 +else: + # 如果一致就将用户信息添加到已有用户列表,并提示用户注册成功 + if passwd == passwd_confirm: + users.append({'user': username, 'pwd': passwd}) + print('恭喜你!注册成功', users) + # 如果不一致就提示用户两次输入的密码不一致 + else: + print('两次输入的密码不一致!') + + +""" +4、整理笔记 + +================================= + Notes +Author: Flora Chen +-_- -_- -_- -_- -_- -_- -_- -_- +================================= + +******for循环****** +1. 定义 +for i in xxx: + # 循环体 + +2. 遍历字符串 +示例: +str1 = 'flora' +for i in str1: + print(i) + +3. 遍历列表 +示例: +# 当前有10位同学的成绩,在一个列表中,请区分成绩的等级 +li = [90, 78, 56, 89, 65, 80, 74, 34, 89, 100] +for score in li: + if 0 < score < 60: + print('成绩{}:不及格'.format(score)) + elif 60 <= score < 80: + print('成绩{}:及格'.format(score)) + elif 80 <= score < 90: + print('成绩{}:优秀'.format(score)) + else: + print('成绩{}:非常优秀'.format(score)) + +4. 遍历字典 +示例: +dic1 = {'name': 'flora', 'gender': 'girl', 'age': 18} +for i in dic1.keys(): + print('遍历字典的键:', i) + +for i in dic1.values(): + print('遍历字典的值:', i) + +for i in dic1.items(): + print('遍历字典的键值对:', i) + +# 遍历字典键值对时,用2个变量分别保存键和值。 +# for i in dic1.items(): +# k, v = i +# print('遍历字典的键:', k) +# print('遍历字典的值:', v) + +for k, v in dic1.items(): + print('遍历字典的键:', k) + print('遍历字典的值:', v) + +5. for循环中的break, continue +示例: +# 需求一:打印10遍hello python +for i in range(1, 11): + print('1: 这是第{}遍: hello python'.format(i)) + +# 需求二:打印到第50遍跳出循环 +for i in range(1, 11): + print('2: 这是第{}遍: hello python'.format(i)) + if i == 5: + break + +# 需求三:第3~5遍不打印 +for i in range(1, 11): + if 3 <= i <= 5: + continue + print('3:这是第{}遍: hello python'.format(i)) + +6. for循环中的高级语法:for -- else +for对应的else语句,只有当循环是通过break结束的时候,不会执行。其他情况下都会执行。 +示例: +for i in range(10): + print('本轮遍历的数据为{}'.format(i)) +else: + print('for对应的else语句') + +示例: +users = [{'user': 123}, {'user': 122}, {'user': 124}] +user = input('请输入您的账号:') +for i in users: + if user == str(i['user']): + print('用户已存在!') + break + else: + print('用户不存在!') +# 缺陷:输入1111,会打印3遍:用户不存在 + +for i in users: + if user == str(i['user']): + print('用户已存在!') + break +else: + print('用户不存在!') + + + +******内置函数range()****** +range(n): 默认生成0 ~ n-1的整数序列。对于这个序列,我们可以通过list()转化为列表类型的数据。 +range(n, m):左闭右开,默认生成从n ~ m-1的整数序列。 对于这个序列,我们可以通过list()转化为列表类型的数据。 +range(n, m , k):左闭右开,n初始值,m-1结束值, k步长, 递增或者递减的整数序列。 + 默认生成从n ~ m-1,并且间隔k的整数序列。 对于这个序列,我们可以通过list()转化为列表类型的数据。 + +# 示例: +print(list(range(10))) # 输出结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +print(list(range(1, 10))) # 输出结果: [1, 2, 3, 4, 5, 6, 7, 8, 9] +print(list(range(2, 8, 2))) # 输出结果: [2, 4, 6] + +print(list(range(101, 5, -5))) +# 输出结果: [101, 96, 91, 86, 81, 76, 71, 66, 61, 56, 51, 46, 41, 36, 31, 26, 21, 16, 11, 6] + +print(list(range(5, 101, 5))) +# 输出结果: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] + + + +******元组拆包***** +示例: +tu = (111, 222) +a, b = tu +print(a, b) # 输出结果:111 222 + + +******函数***** +1. 常用的内置函数 +type():查看数据的类型 +id(): 查看数据的内存地址 +len():查看数据的长度 +range(): 生成数据 + +2. 函数的定义 +def 函数名(): + # 函数内部的功能代码 + # 函数内部的功能代码 + # 函数内部的功能代码 + +可以将单一的功能封装成一个函数,在需要使用该功能的时候直接调用函数就可以了。 +函数的作用: 封装代码。 +函数的意义:提高代码的重用率。 +函数的命名规范:可以由数字下划线组成,不能使用数字开头;不能使用python关键字,不要和内置函数和模块(第三方模块,官方库)重名。 +函数的命名风格:推荐使用下划线命名法。 + +示例: +def func(n): + for i in range(n): + for j in range(i + 1): + print('* ', end='') + print() +func(5) + +3. 函数的参数:定义在函数后面的括号中 +定义的参数叫形参,调用函数的时候传入的参数叫实参。 +示例: +def add_number(a, b): + print('a+b: ', a + b) +add_number(3, 5) + +4. 函数的返回值:return +# 注意:如果接收到的数据为None, 说明没有返回值 +示例: +def add_number(a, b): + return a + b +res = add_number(3, 5) +print(res) + + + + +""" diff --git a/python27Class/homeWork/python/FloraHomeWork_0220.py b/python27Class/homeWork/python/FloraHomeWork_0220.py new file mode 100644 index 0000000..57b1d84 --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0220.py @@ -0,0 +1,125 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/21 09:57 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、有1 2 3 4这四个数字,设计程序计算能组成多少个互不相同且无重复数字的3位数?分别是什么?(思路提示:其实就是数学排列组合,C4取3,三层for循环嵌套可以实现) +""" +count = 0 +for i in range(1, 5): + for j in range(1, 5): + for m in range(1, 5): + if (i != j) and (i != m) and (j != m): + # i != j != m 这个是错误的! + count += 1 + print('第{}次组合:{} {} {}'.format(count, i, j, m)) + +""" +2、小明有100块钱 ,需要买100本书(钱要刚好花完),a类数5元一本,b类书3元一本,c类书0.5元一本;请计算小明有多少种购买的方式? +""" + + +def buy_book(money, book_amount): + # 定义书本单价 + a_book = 5.00 + b_book = 3.00 + c_book = 0.50 + # 如果规定了每类书都要必须购买至少1本的话,用range(1, book_amount+1) + for num1 in range(book_amount + 1): + for num2 in range(book_amount + 1): + for num3 in range(book_amount + 1): + if (money == (a_book * num1) + (b_book * num2) + (c_book * num3)) and ( + book_amount == num1 + num2 + num3): + print('小明购买了{}本书,其中A类书{}本,B类书{}本, C类书{}本,总花费{:.2f}元。'.format(book_amount, num1, num2, num3, money)) + + +buy_book(100.00, 100) + +# musen老师的代码 +count = 0 +for a in range(100 // 5 + 1): + for b in range(100 // 3 + 1): + if a * 5 + b * 3 + (100 - a - b) * 0.5 == 100: + count += 1 + print('小明购买了100本书,其中A类书{}本,B类书{}本, C类书{}本,总花费100元。'.format(a, b, (100 - a - b))) +print('一共有{}种买法'.format(count)) +""" +4、定义一个可以完成任意个数字相加的函数(支持关键字传参和位置传参),并返回相加结果。 +要求: +调用函数传入1个数字,返回值为这个数字。 如:func(1) - ---> 返回1 +调用函数传入2个数字,返回值为2个数相加的结果。 如:func(11, 22) - ---> 返回33 +调用函数传入3个数字,返回值为3个数相加的结果。 如:func(11, 22, 33, ) - ---> 返回66 +调用函数传入n个数字,返回值为n个数相加的结果。 如:func(1, 2, 3, 4, 5) - ---> 返回15 +(提示:可以使用不定长参数来接收参数,对参数进行遍历再相加) +""" + + +# 方法一 +def add_number(*args, **kwargs): + result = 0 + for num in args: + result += num + # for num1 in kwargs.values: + # result += num1 + for num1 in kwargs: + result += kwargs[num1] + return result + + +print(add_number(1)) +print(add_number(1, 2, 3, 4, 5)) +print(add_number(a=1, b=2, c=3, d=4, e=5)) +print(add_number(11, b=33)) + +# 方法二 比较笨,忽略 +# def get_numbers(*args, **kwargs): +# global li +# li = list(args) +# dic = dict(kwargs) +# for a in dic.values(): +# li.append(a) +# return li +# +# def add_number(): +# result = 0 +# for b in li: +# result = result + b +# return result +# +# get_numbers(1) +# print(add_number()) +# +# get_numbers(11, 22) +# print(add_number()) +# +# get_numbers(11, b=33) +# print(add_number()) +# +# get_numbers(a=1, b=2, c=3, d=4, e=5) +# print(add_number()) + + + +""" +4:简单题 +1、什么是全局变量? + 全局变量:直接定义在文件/模块中的变量。在该文件的任何地方都可以访问。 + +2、什么是局部变量? + 局部变量:定义在函数内部的变量。只有在函数内部才可以访问。 + +3、函数内部如何声明全局变量 ? + 使用global声明,例如 global a + +4、函数的形参有哪几种定义形式? + 形参的分类: + 必备参数(必须参数):定义了几个参数就要传递几个参数。 + 默认参数(缺省参数):可传可不传,不传的情况下使用默认值,传了的情况下使用传的值。 + 不定长参数:位置可前可后,但是一般放在后面。 + *args:接收0个或多个位置参数 + **kwargs:接收0个或多个关键字参数 +""" diff --git a/python27Class/homeWork/python/FloraHomeWork_0222.py b/python27Class/homeWork/python/FloraHomeWork_0222.py new file mode 100644 index 0000000..11558cd --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0222.py @@ -0,0 +1,219 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/22 19:27 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +# 第一题:现有数据如下 +users_title = ["name", "age", "gender"] +users_info = [['小明', 18, '男'], ["小李", 19, '男'], ["小美", 17, '女']] + +# 要求:请封装一个函数,上述两个列表作为参数传入,返回值为如下数据(提示:需要用到zip和for循环) +users = [{'name': '小明', 'age': 18, 'gender': '男'}, + {'name': '小李', 'age': 19, 'gender': '男'}, + {'name': '小美', 'age': 17, 'gender': '女'}] +""" +users_title = ["name", "age", "gender"] +users_info = [['小明', 18, '男'], ["小李", 19, '男'], ["小美", 17, '女']] + +def user_func(title, info): + users = [] + for item in info: + users.append(dict(zip(title, item))) + return users + +result = user_func(users_title, users_info) + +# 按照老师题目中给出的格式输出 +# new_result = 'users = [' + str(result[0]) + ',\n ' + str(result[1]) + ',\n ' + str(result[2]) + ']' +new_result = 'users = [{},\n{:>49},\n{:>49}]'.format(str(result[0]), str(result[1]), str(result[2])) +print(new_result) + + +# 弯弯绕绕的解题方法 +# def user_func(title_len, *args): +# # 定义3个列表来接收新的列表 +# users_title2 = [] +# users_info2 = [] +# users = [] +# +# # 遍历传入的不定长参数,将值分情况保存到新列表中 +# for item in args: +# if title_len <= 0: +# users_info2.append(item) +# else: +# users_title2.append(item) +# title_len -= 1 +# +# # 对两个新列表进行打包,并转换成字典格式,然后保存在列表中 +# for a in users_info2: +# users.append(dict(zip(users_title2, a))) +# +# # 返回新列表 +# return users +# +# print(user_func(len(users_title), *users_title, *users_info)) + + +""" +第二题:请封装一个函数,按要求实现数据的格式转换 +# 传入参数: data = ["{'a':11,'b':2}", "[11,22,33,44]"] +# 返回结果:res = [{'a': 11, 'b': 2}, [11, 22, 33, 44]] +# 通过代码将传入参数转换为返回结果所需数据,然后返回 +""" +# 使用必备参数 +def transform_data1(li): + res = [] + for param in li: + res.append(eval(param)) + return res + +data = ["{'a':11,'b':2}", "[11,22,33,44]"] +print(transform_data1(data)) + +# 使用不定长参数 +def transform_data2(*args): + res = [] + for param in args: + res.append(eval(param)) + return res + +data = ["{'a':11,'b':2}", "[11,22,33,44]"] +print(transform_data2(*data)) + + + +""" +第三题:当前有一个data.txt文件,内容如下: +数据aaa +数据bbb +数据ccc +数据ddd + +# 要求:请将数据读取出来,保存为以下格式 + {'data0': '数据aaa', 'data1': '数据bbb', 'data2': '数据ccc', 'data3': '数据ddd'} + ​ +# 提示思路: + #1、按行读取数据,2、构造字典的键, 3、打包为字典 + ​ + # 注意点:读取出来的数据有换行符'\n',要想办法去掉 +""" +# --------------------方法1-------------------- +# 读取文件的内容 +with open('data.txt', 'r', encoding='utf-8') as f: + data_value = [] + data_key = [] + datas = f.readlines() + for i in range(len(datas)): + data_key.append("data{}".format(i)) + data_value.append(datas[i].replace('\n', '')) + data = dict(zip(data_key, data_value)) + +# --------------------方法2-------------------- +# 读取数据,每一行作为一个元素放到列表中 +with open('data.txt', 'r', encoding='utf-8') as f: + datas = f.readlines() +# 创建一个空字典 +dic = {} +# 通过enumerate去获取列表中的数据和下标 +for index, data in enumerate(datas): + key = 'data{}'.format(index) + value = data.replace('\n', '') + # 加入到字典中 + dic[key] = value + +# --------------------方法3-------------------- + +with open('data.txt', 'r', encoding='utf-8') as f: + data_value = [] + data_key = ['data0', 'data1', 'data2', 'data3'] + for i in f.readlines(): + new_i = i.split('\n') + data_value.append(new_i[0]) + data = dict(zip(data_key, data_value)) + + +# 覆盖写入保存后的数据 +with open('data.txt', 'w', encoding='utf-8') as f: + f.write(str(data)) + + +""" +4、继续扩展石头剪刀布的游戏,想办法把每次游戏结果都写入到txt文件中保存,文件中写入内容格式如下: +""" + + +import random +# --------------------方法1-------------------- +# 猜拳小游戏 +def game(): + print('---石头剪刀布游戏开始---') + print('请按照下面的提示出拳:') + li = ['石头', '剪刀', '布'] + game_results = [] + while True: + print('石头【1】/剪刀【2】/布【3】/结束游戏【4】') + user_num = int(input('请输入你的选项:')) + r_num = random.randint(1, 3) + print(r_num) + if 1 <= user_num <= 3: + if r_num == user_num: + res1 = '您的出拳为:{}, 电脑出拳:{},平局'.format(li[user_num - 1], li[r_num - 1]) + game_results.append(res1) + print(res1) + elif (user_num - r_num) == -1 or (user_num - r_num) == 2: + res2 = '您的出拳为:{}, 电脑出拳:{},您胜利了'.format(li[user_num - 1], li[r_num - 1]) + game_results.append(res2) + print(res2) + else: + res3 = '您的出拳为:{}, 电脑出拳:{},您输了'.format(li[user_num - 1], li[r_num - 1]) + game_results.append(res3) + print(res3) + elif user_num == 4: + res4 = '游戏结束!' + game_results.append(res4) + print(res4) + break + else: + res5 = '您出拳有误,请按规矩出拳!!' + game_results.append(res5) + print(res5) + return game_results + +# 将猜拳小游戏的结果覆盖写入文件中 +def save_game(): + # 追加写入游戏结果 + with open('game.txt', 'w', encoding='utf-8') as f: + for game_result in game(): + f.write(game_result + '\n') + +# 调用函数 +# save_game() + + +# --------------------方法2-------------------- +with open('game.txt', 'w', encoding='utf-8') as f: + print('---石头剪刀布游戏开始---') + print('请按照下面的提示出拳:') + li = ['石头', '剪刀', '布'] + game_results = [] + while True: + print('石头【1】/剪刀【2】/布【3】/结束游戏【4】') + user_num = int(input('请输入你的选项:')) + r_num = random.randint(1, 3) + print(r_num) + if 1 <= user_num <= 3: + if r_num == user_num: + f.write('您的出拳为:{}, 电脑出拳:{},平局\n'.format(li[user_num - 1], li[r_num - 1])) + elif (user_num - r_num) == -1 or (user_num - r_num) == 2: + f.write('您的出拳为:{}, 电脑出拳:{},您赢了\n'.format(li[user_num - 1], li[r_num - 1])) + else: + f.write('您的出拳为:{}, 电脑出拳:{},您输了\n'.format(li[user_num - 1], li[r_num - 1])) + elif user_num == 4: + f.write('游戏结束!\n') + break + else: + f.write('您出拳有误,请按规矩出拳!\n') \ No newline at end of file diff --git a/python27Class/homeWork/python/FloraHomeWork_0225.py b/python27Class/homeWork/python/FloraHomeWork_0225.py new file mode 100644 index 0000000..46459eb --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0225.py @@ -0,0 +1,234 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/25 19:27 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、实现一个文件复制器函数,通过给函数传入一个路径,复制该路径下面所有的文件(目录不用复制)到当前目录, + + 提示:os模块结合文件读写操作 、即可实现 + +步骤提示:获取指定路径下的所有文件信息,判断是否是文件,是文件则进行复制(读取内容,写入到新文件) +""" + +import os + + +# ------------------方法1-------------------- +# 复制指定路径下的文件到当前文件所在的目录 +def file_copy(path): + # 如果传入的是个目录就进行遍历文件复制 + if os.path.isdir(path): + for file in os.listdir(path): + # 定位目标目录的文件 + file_path = os.path.join(path, file) + + # 如果是文件,则进行文件复制 + if os.path.isfile(file_path): + # 读取文件的内容 + with open(file_path, 'rb') as f: + content = f.read() + + # 将上面读取到的内容写入到新文件中, 新文件跟当前文件同级,并且命名带有cp + # with open(os.path.join(os.getcwd(), 'cp' + file), 'wb') as f: + with open('cp' + file, 'wb') as f: + f.write(content) + + # 如果是文件的话,则直接复制 + elif os.path.isfile(path): + # 读取文件的内容 + with open(path, 'rb') as f: + content = f.read() + + # 将上面读取到的内容写入到新文件中, 新文件跟当前文件同级,并且命名带有cp + # with open(os.path.join(os.getcwd(), 'cp' + file), 'wb') as f: + with open('cp' + path, 'wb') as f: + f.write(content) + + + +# 需要复制的文件所在的目录 +target_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Pack') + +file_copy(target_path) + + +# 复制当前文件所在目录下的所有文件到指定目录 +# def files_copy(directory_name, path): +# # 判断当前工作路径下是否存在文件 +# for file in os.listdir(path): +# # 在当前工作目录下面创建一个与当前文件同级的目录来保存复制的文件。不存在则创建。 +# if directory_name not in os.listdir(path): +# os.mkdir(directory_name) +# +# # 如果是文件,则进行文件复制 +# if os.path.isfile(file): +# # 在新目录下新建文件,读取当前工作目录下文件的内容 +# with open(file, 'rb') as f: +# content = f.read() +# +# # 将上面读取到的内容写入到新文件中 +# with open(os.path.join(directory_name, 'cp' + file), 'wb') as f: +# f.write(content) + +# files_copy('TestDirectory', os.getcwd()) + + + + +# ------------------方法2-------------------- +# def copy_file(file): +# # 获取文件名以及后缀 +# dest_file = 'cp' + os.path.basename(file) +# +# # 读取文件内容 +# with open(file, 'rb') as f: +# content = f.read() +# +# # 在新文件中写入内容 +# with open(dest_file, 'wb') as f: +# f.write(content) +# +# +# def is_file(path): +# # 获取当前目录下的所有文件 +# for file in os.listdir(path): +# # 获取所有文件的绝对路径 +# file_path = os.path.join(path, file) +# +# # 判断是否是文件,是文件就调用copy_file +# if os.path.isfile(file_path): +# copy_file(file_path) +# +# +# is_file(target_path) + +""" +case.txt文件,里面中存储了很多用例数据: 如下,每一行数据就是一条用例数据, + # 文件中数据(可以先直接复制到文件中) + url:www.baidu.com,mobilephone:13760246701,pwd:123456 + url:www.baidu.com,mobilephone:15678934551,pwd:234555 + url:www.baidu.com,mobilephone:15678934551,pwd:234555 + url:www.baidu.com,mobilephone:15678934551,pwd:234555 + url:www.baidu.com,mobilephone:15678934551,pwd:234555 + + # 要求: 请把这些数据读取出来,转换为列表的格式:如下 + [{'url': 'www.baidu.com', 'mobilephone': '13760246701', 'pwd': '123456'}, {'url': 'www.baidu.com', 'mobilephone': '15678934551', 'pwd': '234555'},{'url': 'www.baidu.com', 'mobilephone': '15678934551', 'pwd': '234555'},{'url': 'www.baidu.com', 'mobilephone': '15678934551', 'pwd': '234555'}, + {'url': 'www.baidu.com', 'mobilephone': '15678934551', 'pwd': '234555'}] + ​ + # 提示:可以分析读取出来的每一行字符串中的内容,然后使用的字符串分割方法进行分割,想办法组装成字典。 + # 注意点:数据中如果有换行符'\n',要想办法去掉 +""" + + +# ------------------方法1-------------------- +def read_data(file): + # 定义3个空列表来接收数据 + key = [] + value = [] + case = [] + # 读取文件中的内容 + with open(file, 'r', encoding='utf-8') as f: + # 将读取的每一行内容使用‘,’分割 + for i in f.readlines(): + res = i.split(',') + # 遍历分割后的列表,将元素的值分别追加到列表key和value中 + for j in res: + res2 = j.split(':') + key.append(res2[0]) + value.append(res2[1].replace('\n', '')) + # 将两个新列表打包成字典并追加到列表case中 + case.append(dict(zip(key, value))) + return case + + +print(read_data('case.txt')) + + +# ------------------方法2-------------------- +def analyse(file): + # 定义一个空列表来接收数据 + case_list = [] + + # 打开文件 + with open(file, 'r') as f: + # 按行读取文件中所有的内容 + for line in f.readlines(): + # 定义一个空字典来接收每一行的数据 + case = {} + # 将每行内容使用逗号分隔 + for sub in line.split(','): + # 再将列表中的每个元素用冒号分割 + flied = sub.split(':') + + # 如果有换行,则去除;并且# 给字典新增键值对 + if flied[1].endswith('\n'): + case[flied[0]] = flied[1][:-1] + else: + case[flied[0]] = flied[1] + # 三目运算符 等同于上面的代码 + # value[flied[0]] = flied[1][:-1]if flied[1].endswith('\n') else flied[1] + + # 将得到的字典追加到列表中 + case_list.append(case) + return case_list + + +print(analyse('case.txt')) + +""" +3、第三题:练习模块导入的方式(不用提交) +Pass +""" + +""" +4、整理笔记 +""" + +""" +5、编程逻辑扩展练习题(不用提交) +(1)有一个猴子,第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半 在加一个。到第10天早上想再吃时,见只剩下一个桃子了。 +请通过一段通过代码来计算 第一天摘了多少个桃子? + + +(2)题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在第10次落地时,共经过多少米? +""" + + +def monkey(days): + peach = 1 + for day in range(1, days): + peach = (peach + 1) * 2 + print('小猴子第1天总共摘了{}桃子'.format(peach)) + return peach +print(monkey(10)) + + +# def monkey(days): +# peach = 1534 +# for day in range(1, days + 1): +# eat_peach = peach / 2 + 1 +# peach = peach - eat_peach +# print('小猴子第{}天总共吃了{}桃子, 剩余{}'.format(day, eat_peach, peach)) +# return peach +# +# +# print(monkey(10)) + + +def ball(height, times): + count_height = 0 + for count in range(1, times + 1): + if count == 1: + count_height = height + else: + count_height = count_height + height * 2 + height = height / 2 + print('第{}次落地剩余{}米, 总共经过{}米'.format(count, height, count_height)) + return count_height + + +print(ball(100, 10)) diff --git a/python27Class/homeWork/python/FloraHomeWork_0227.py b/python27Class/homeWork/python/FloraHomeWork_0227.py new file mode 100644 index 0000000..f399e1b --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0227.py @@ -0,0 +1,112 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/26 19:17 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import random + +""" +1、优化之前作业的石头剪刀布游戏,用户输入时,如果输入非数字会引发异常,请捕获这个异常,提示用户重新输入。 +""" + + +def game(): + with open('game.txt', 'w', encoding='utf-8') as f: + print('---石头剪刀布游戏开始---') + print('请按照下面的提示出拳:') + li = ['石头', '剪刀', '布'] + while True: + print('石头【1】/剪刀【2】/布【3】/结束游戏【4】') + try: + user_num = int(input('请输入你的选项:')) + except Exception as e: + f.write('捕获到的异常是:{}\n'.format(str(e))) + print('请重新输入你的选项!') + else: + r_num = random.randint(1, 3) + print(r_num) + if 1 <= user_num <= 3: + if r_num == user_num: + result = '您的出拳为:{}, 电脑出拳:{},平局\n'.format(li[user_num - 1], li[r_num - 1]) + + elif (user_num - r_num) == -1 or (user_num - r_num) == 2: + result ='您的出拳为:{}, 电脑出拳:{},您赢了\n'.format(li[user_num - 1], li[r_num - 1]) + else: + result ='您的出拳为:{}, 电脑出拳:{},您输了\n'.format(li[user_num - 1], li[r_num - 1]) + f.write(result) + elif user_num == 4: + print('游戏结束!\n') + break + else: + print('您出拳有误,请按规矩出拳!\n') + + + +game() + +""" +2、写出异常处理语句中try作用是什么,except,else,finally下面的代码分别在什么时候会执行?(简答题) +答案: +try是用来捕获异常的 +except的代码在发生异常的时候会执行 +else的代码在没有发生异常的时候会执行 +finally的代码不管是否捕获到异常都会执行 +""" + +""" +3、用户输入一个数值,打印1到这个数值之间所有的偶数、及其偶数个数、及其它们的平均值(如果输入非数值,请让用户重新输入) +""" + +# 输入0, 1, 负数会报错 ZeroDivisionError: division by zero +# result = sum(even_numbers) / len(even_numbers) +def numbers(): + while True: + # 定义一个空列表来接收偶数 + even_numbers = [] + # 捕获异常 + try: + number = int(input('请输入一个数值:')) + # 如果捕获到了异常就打印出捕获的异常 + except Exception as e: + print('捕获到了异常:{}'.format(e)) + print('您的输入有误,请重新输入!') + # 如果没有捕获到异常,就去计算1到该数值之间的偶数 + else: + for num in range(1, number + 1): + if int(num % 2) == 0: + even_numbers.append(num) + print('1到该数值之间的偶数有:{}'.format(num)) + result = sum(even_numbers) / len(even_numbers) + print('1到该数值之间的偶数总共有{}个, 它们的平均值是{}'.format(len(even_numbers), result)) + break + + +numbers() + +""" +4、整理笔记 +""" + +""" +5、逻辑扩展题(不用提交): +1、小明买了一对刚出生的兔子,兔子从出生后第3个月起每个月都生一对兔子,生的这对小兔子长到第三个月也开始生兔子(每个月生一对兔子) +假如兔子都不死,问10个月后小明的兔子为多少对?(思路提示:重点在分析出兔子增长的规律,分析出规则之后通过for循环即可实现) +""" + +# month表示第几个月后兔子达到的数量 interval表示间隔几个月,兔子会再生兔子 +def cal_rabbit(month, interval): + first_rabbit = 1 + rabbits = [] + for i in range(1, month + 1): + if 1 <= i < 3: + rabbits.append(first_rabbit) + print('第{}月兔子的数量为{}'.format(i, rabbits[i-1])) + else: + rabbits.append(rabbits[i - (interval+1)] + rabbits[i - interval]) + print('第{}月兔子的数量为{}'.format(i, rabbits[i-1])) + print('10个月后小明的兔子为:{}'.format(rabbits[-1])) + +cal_rabbit(10, 2) + diff --git a/python27Class/homeWork/python/FloraHomeWork_0229.py b/python27Class/homeWork/python/FloraHomeWork_0229.py new file mode 100644 index 0000000..d783e1b --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0229.py @@ -0,0 +1,111 @@ +""" +================================= +Author: Flora Chen +Time: 2020/2/29 9:22 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、类属性怎么定义? 实例属性怎么定义? +答案: + 类属性是定义在类里面的属性。属性名=属性值。 + 实例属性是通过实例对象来定义的属性。对象.属性名=属性值。 +""" + + +class ClassDefine: + # 这是类属性 + attribute_01 = '类属性1' + attribute_02 = '类属性2' + + # 实例属性 + def __init__(self, attr_03, attr_04): + self.attr_03 = attr_03 + self.attr_04 = attr_04 + + +""" +2、实例方法中的self代表什么?(简答) +答案: + self代表实例化对象本身。 + self代表实例对象。 + 实例对象生成以后,要实现功能,它必须要去调用类里的属性和方法,所以类里面的self就是,哪个实例对象在调用类里的代码,self就代表谁。定义类时代码要引用实例属性和实例对象的,也都需要self.来调用。 +""" + +""" +3、类中__init__方法在什么时候会调用的?(简答) +答案: + 类中__init__方法在实例化对象的时候会调用。 + __init__()方法可以创建实例属性,__init__()方法就是初始化方法。 + 当你创建一个实例对象的时候,这个函数就会被调用。 + 即:在执行 实例对象 = 类()的语句时,就会自动调用__init__(self)函数。 +""" + +""" +4、定义一个登录的测试用例类LoginTestCase + +登录url地址为:"http://www.xxxx.com/login" +请求方法为:"post" 、 + +请自行分辨下列属性,应该定义为类属性还是实例属性 + +- 属性: +用例编号 +url地址 +请求参数 +请求方法 +预期结果 +实际结果 +""" + + +class LoginTestCase: + # 类属性 + url = "http://www.xxxx.com/login" + method = "post" + + # 实例属性 + def __init__(self, case_num, para, except_result, actual_result): + self.case_num = case_num # 用例编号 + self.para = para # 请求参数 + self.except_result = except_result # 预期结果 + self.actual_result = actual_result # 实际结果 + + +""" +5、封装一个学生类,(自行分辨定义为类属性还是实例属性,方法定义为实例方法) + +- 属性:身份(学生),姓名,年龄,性别,英语成绩,数学成绩,语文成绩, + +- 方法一:计算总分,方法二:计算三科平均分,方法三:打印学生的个人信息:我的名字叫XXX,年龄:xxx, 性别:xxx。 +""" + + +class Student: + identity = '学生' + + def __init__(self, name, age, gender, english_score, math_score, language_score): + self.name = name + self.age = age + self.gender = gender + self.english_score = english_score + self.math_score = math_score + self.language_score = language_score + + def sum_score(self): + score = self.english_score + self.math_score + self.language_score + return score + + def avg_score(self): + avg = self.sum_score() / 3 + return avg + + def student_info(self): + print('我的名字叫{},年龄:{}, 性别:{}。'.format(self.name, self.age, self.gender)) + + +student = Student('flora', 23, 'female', 89, 90, 100) +print(student.sum_score()) +print(student.avg_score()) +student.student_info() diff --git a/python27Class/homeWork/python/FloraHomeWork_0303.py b/python27Class/homeWork/python/FloraHomeWork_0303.py new file mode 100644 index 0000000..093c28e --- /dev/null +++ b/python27Class/homeWork/python/FloraHomeWork_0303.py @@ -0,0 +1,96 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/3 19:48 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +""" +1、上课的手机类继承代码自己敲一遍进行提交, +""" +class PhoneV1(object): + def call(self): + print('打电话的功能') + +class PhoneV2(PhoneV1): + def listen_music(self): + print('听音乐的功能') + + def send_message(self): + print('发短信的功能') + +class PhoneV3(PhoneV2): + def we_chat(self): + print('聊微信的功能') + + def play_game(self): + print('玩游戏的功能') + +# v1对应的类 +print('------v1对应的类------') +v1 = PhoneV1() +v1.call() +# 父类不能调用子类的方法 +# v1.listen_music() # 报错:AttributeError: 'PhoneV1' object has no attribute 'listen_music' + +# v2对应的类 +print('------v2对应的类------') +v2 = PhoneV2() +# 子类可以调用父类的方法 +v2.call() +v2.listen_music() +v2.send_message() + +# v3对应的类 +print('------v3对应的类------') +v3 = PhoneV3() +v3.call() +v3.listen_music() +v3.send_message() +v3.we_chat() +v3.play_game() + + +""" +2、有一组数据,如下格式: +{'case_id': 1, 'method': 'post', 'url': '/member/login', 'data': '123', 'actual': '不通过','excepted': '通过'}, +定义一个如下的类,请通过setattr将上面字典中的键值对,分别设置为类的属性和属性值,键作为属性名,对应的值作为属性值 + +class CaseData: + pass +""" +# 定义一个类 +class CaseData: + pass + +# 定义一组数据 +data = {'case_id': 1, 'method': 'post', 'url': '/member/login', 'data': '123', 'actual': '不通过','excepted': '通过'} + +# 将上面字典中的key设置为属性名,value设置为属性值 +for key, value in data.items(): + # 动态设置类的属性 + setattr(CaseData, key, value) + +# 实例化对象 +case = CaseData() +# 通过实例化对象访问类中的类属性 +print('通过实例化对象访问类中的类属性:', case.case_id) +print('通过实例化对象访问类中的类属性:', case.method) +print('通过实例化对象访问类中的类属性:', case.url) +print('通过实例化对象访问类中的类属性:', case.data) +print('通过实例化对象访问类中的类属性:', case.actual) +print('通过实例化对象访问类中的类属性:', case.excepted) + +# 通过类访问类中的类属性 +print('通过类访问类中的类属性:', CaseData.case_id) +print('通过类访问类中的类属性:', CaseData.method) +print('通过类访问类中的类属性:', CaseData.url) +print('通过类访问类中的类属性:', CaseData.data) +print('通过类访问类中的类属性:', CaseData.actual) +print('通过类访问类中的类属性:', CaseData.excepted) + + +""" +3、python基础语法到此就差不多结束了,本次不布置过多的作业,将基础阶段的基本语法,内容先消化一下,后面就是类的各种应用了 +""" diff --git a/python27Class/homeWork/unitTest/homeWork03052020/registerPage.py b/python27Class/homeWork/unitTest/homeWork03052020/registerPage.py new file mode 100644 index 0000000..02a9215 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03052020/registerPage.py @@ -0,0 +1,68 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 8:59 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +users = [{'user': 'python26', 'password': '123456'}] + + +def register(username, password1, password2): + """ + + :param username: + :param password1: + :param password2: + :return: + """ + # 判断是否有参数为空 + if not all([username, password1, password2]): + return {"code": 0, "msg": "所有参数不能为空"} + # 注册功能 + for user in users: # 遍历出所有账号,判断账号是否存在 + if username == user['user']: + # 账号存在 + return {"code": 0, "msg": "该账户已存在"} + else: + if password1 != password2: + # 两次密码不一致 + return {"code": 0, "msg": "两次密码不一致"} + else: + # 账号不存在 密码不重复,判断账号密码长度是否在 6-18位之间 + if 6 <= len(username) >= 6 and 6 <= len(password1) <= 18: + # 注册账号 + users.append({'user': username, 'password': password2}) + return {"code": 1, "msg": "注册成功"} + else: + # 账号密码长度不对,注册失败 + return {"code": 0, "msg": "账号和密码必须在6-18位之间"} + + +if __name__ == "__main__": + res = register('python14', '123456', '123456') + print(res) + +""" +函数入参: +注意:参数传字符串类型,不需要考虑其他类型。 +参数1:账号 +参数2:密码1 +参数2:密码2 + + +函数内部处理的逻辑: + 判断是否有参数为空, + 判断账号密码是否在6-18位之间, + 判断账号是否被注册过, + 判断两个密码是否一致。 + 上面添加都校验通过才能注册成功,其他情况都注册失败, +各种情况的返回结果如下: + 注册成功 返回结果:{"code": 1, "msg": "注册成功"} + 有参数为空, 返回结果 {"code": 0, "msg": "所有参数不能为空"} + 两次密码不一致 返回结果:{"code": 0, "msg": "两次密码不一致"} + 账户已存在 返回结果:{"code": 0, "msg": "该账户已存在"} + 密码不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} + 账号不在6-18位之间 返回结果:{"code": 0, "msg": "账号和密码必须在6-18位之间"} +""" \ No newline at end of file diff --git a/python27Class/homeWork/unitTest/homeWork03052020/runTest.py b/python27Class/homeWork/unitTest/homeWork03052020/runTest.py new file mode 100644 index 0000000..f67f17a --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03052020/runTest.py @@ -0,0 +1,65 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 9:33 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest +import os +from BeautifulReport import BeautifulReport +from HTMLTestRunner import HTMLTestRunner + +# 要执行的测试用例的位置 +path =os.path.dirname(os.path.abspath(__file__)) +""" +第一步:创建测试套件 +""" +# suite = unittest.TestSuite() + +""" +第二步:加载测试用例到测试套件 +# 第三种:通过路径去加载所有的测试用例 (推荐这一种) +# 注意:默认去找指定路径中test开头的模块中的测试用例 +""" +# loader = unittest.TestLoader() +# suite.addTest(loader.discover(path)) + +""" +综合第一步和第二步:创建套件并加载用例 +""" +suite= unittest.defaultTestLoader.discover(path) + +""" +第三步:(1)执行测试套件中的用例(没有漂亮的HTML报告,只在控制台简单显示测试结果) +""" +# runner = unittest.TextTestRunner() +# runner.run(suite) + +# 测试报告存放的路径 +report_path = os.path.join(path, 'testReport') + +""" +第三步:(2)执行测试套件中的用例, 使用BeautifulReport生成HTML测试报告 +2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" +b_report = BeautifulReport(suite) +b_report.report('Register Function Report by flora', + 'register_beautiful_report.html', + report_dir=report_path + ) + +""" +第三步:(3)执行测试套件中的用例, 使用HTMLTestRunner生成HTML测试报告 +stream表示报告存放的位置文件名以及写入的模式 +title表示报告的标题 +tester表示测试人员 +description表示对测试报告的描述 +""" +# runner = HTMLTestRunner(stream=open(os.path.join(report_path, 'register_tr_report.html'), 'wb'), +# title='Register Function Report', +# tester='flora.chen', +# description='Version 1.0') +# runner.run(suite) + diff --git a/python27Class/homeWork/unitTest/homeWork03052020/testCase.py b/python27Class/homeWork/unitTest/homeWork03052020/testCase.py new file mode 100644 index 0000000..ff6d5a3 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03052020/testCase.py @@ -0,0 +1,97 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/6 9:01 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.homeWork.unitTest.homeWork03052020.registerPage import register + + +class RegisterTestCase(unittest.TestCase): + # 注册成功 + def test_register_pass(self): + # 第一步:准备用例数据 + # 第二步:获取实际结果(调用功能函数,传入参数,获取实际结果) + # 第三步:断言(比对预期结果和实际结果) + + # 参数准备 + user_info = {'username': 'floraachy', 'password1': '12345678Az', 'password2': '12345678Az'} + # 预期结果准备 + expect_result = {"code": 1, "msg": "注册成功"} + # 获取实际结果 + actual_result = register(**user_info) + # 断言 + self.assertEqual(expect_result, actual_result) + + # 注册账号已存在 + def test_register_user_exist(self): + user_info = {'username': 'python26', 'password1': '123456', 'password2': '123456'} + expect_result = {"code": 0, "msg": "该账户已存在"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + # 用户名或者密码1或者密码2为空的情况下注册 + def test_register_user_null(self): + user_info = {'username': None, 'password1': '12345678Az', 'password2': '12345678Az'} + # 以下方式传值会报错,缺少参数 + # user_info = {'password1': '12345678Az', 'password2': '12345678Az'} + expect_result = {"code": 0, "msg": "所有参数不能为空"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + def test_register_pwd1_null(self): + user_info = {'username': 'flora.chen', 'password1': None, 'password2': '12345678Az'} + expect_result = {"code": 0, "msg": "所有参数不能为空"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + def test_register_pwd2_null(self): + user_info = {'username': 'flora.chen', 'password1': '12345678Az', 'password2': None} + expect_result = {"code": 0, "msg": "所有参数不能为空"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + # 两次输入的密码不一致的情况下注册 + def test_register_pwd1_pwd2_unequal(self): + user_info = {'username': 'flora.chen', 'password1': '123456', 'password2': '1234567890'} + expect_result = {"code": 0, "msg": "两次密码不一致"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + # 用户名长度小于6或者大于18的情况下注册 + def test_register_user_length_5(self): + user_info = {'username': 'chen', 'password1': '1234567', 'password2': '1234567'} + expect_result = {"code": 0, "msg": "账号和密码必须在6-18位之间"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + def test_register_user_length_19(self): + user_info = {'username': 'username.username.c', 'password1': '123456789', 'password2': '12345678'} + expect_result = {"code": 0, "msg": "账号和密码必须在6-18位之间"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + # 密码长度小于6或者大于18的情况下注册 + def test_register_pwd_length_5(self): + user_info = {'username': 'flora.chen', 'password1': '12345', 'password2': '12345'} + expect_result = {"code": 0, "msg": "账号和密码必须在6-18位之间"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + + def test_register_pwd_length_19(self): + user_info = {'username': 'flora.chen', 'password1': '1234567890123456789', 'password2': '1234567890123456789'} + expect_result = {"code": 0, "msg": "账号和密码必须在6-18位之间"} + actual_result = register(**user_info) + self.assertEqual(expect_result, actual_result) + +if __name__ == '__main__': + unittest.main() + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03052020/testReport/register_beautiful_report.html b/python27Class/homeWork/unitTest/homeWork03052020/testReport/register_beautiful_report.html new file mode 100644 index 0000000..d436bbf --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03052020/testReport/register_beautiful_report.html @@ -0,0 +1,7449 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/casesData.xlsx b/python27Class/homeWork/unitTest/homeWork03072020/demo1/casesData.xlsx new file mode 100644 index 0000000..2272aa2 Binary files /dev/null and b/python27Class/homeWork/unitTest/homeWork03072020/demo1/casesData.xlsx differ diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/ddtNew.py b/python27Class/homeWork/unitTest/homeWork03072020/demo1/ddtNew.py new file mode 100644 index 0000000..2915330 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo1/ddtNew.py @@ -0,0 +1,319 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 10:52 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +# -*- coding: utf-8 -*- +# This file is a part of DDT (https://github.com/datadriventests/ddt) +# Copyright 2012-2015 Carles Barrobés and DDT contributors +# For the exact contribution history, see the git revision log. +# DDT is licensed under the MIT License, included in +# https://github.com/datadriventests/ddt/blob/master/LICENSE.md + +import inspect +import json +import os +import re +import codecs +from functools import wraps + +try: + import yaml +except ImportError: # pragma: no cover + _have_yaml = False +else: + _have_yaml = True + +__version__ = '1.2.2' + +# These attributes will not conflict with any real python attribute +# They are added to the decorated test method and processed later +# by the `ddt` class decorator. + +DATA_ATTR = '%values' # store the data the test must run with +FILE_ATTR = '%file_path' # store the path to JSON file +UNPACK_ATTR = '%unpack' # remember that we have to unpack values +index_len = 5 # default max length of case index + + +try: + trivial_types = (type(None), bool, int, float, basestring) +except NameError: + trivial_types = (type(None), bool, int, float, str) + + +def is_trivial(value): + if isinstance(value, trivial_types): + return True + elif isinstance(value, (list, tuple)): + return all(map(is_trivial, value)) + return False + + +def unpack(func): + """ + Method decorator to add unpack feature. + + """ + setattr(func, UNPACK_ATTR, True) + return func + + +def data(*values): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + global index_len + index_len = len(str(len(values))) + return idata(values) + + +def idata(iterable): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + def wrapper(func): + setattr(func, DATA_ATTR, iterable) + return func + return wrapper + + +def file_data(value): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + ``value`` should be a path relative to the directory of the file + containing the decorated ``unittest.TestCase``. The file + should contain JSON encoded data, that can either be a list or a + dict. + + In case of a list, each value in the list will correspond to one + test case, and the value will be concatenated to the test method + name. + + In case of a dict, keys will be used as suffixes to the name of the + test case, and values will be fed as test data. + + """ + def wrapper(func): + setattr(func, FILE_ATTR, value) + return func + return wrapper + + +def mk_test_name(name, value, index=0): + """ + Generate a new name for a test case. + + It will take the original test name and append an ordinal index and a + string representation of the value, and convert the result into a valid + python identifier by replacing extraneous characters with ``_``. + + We avoid doing str(value) if dealing with non-trivial values. + The problem is possible different names with different runs, e.g. + different order of dictionary keys (see PYTHONHASHSEED) or dealing + with mock objects. + Trivial scalar values are passed as is. + + A "trivial" value is a plain scalar, or a tuple or list consisting + only of trivial values. + """ + + # Add zeros before index to keep order + index = "{0:0{1}}".format(index + 1, index_len) + if not is_trivial(value): + return "{0}_{1}".format(name, index) + try: + value = str(value) + except UnicodeEncodeError: + # fallback for python2 + value = value.encode('ascii', 'backslashreplace') + test_name = "{0}_{1}_{2}".format(name, index, value) + return re.sub(r'\W|^(?=\d)', '_', test_name) + + +def feed_data(func, new_name, test_data_docstring, *args, **kwargs): + """ + This internal method decorator feeds the test data item to the test. + + """ + @wraps(func) + def wrapper(self): + return func(self, *args, **kwargs) + wrapper.__name__ = new_name + wrapper.__wrapped__ = func + # set docstring if exists + if test_data_docstring is not None: + wrapper.__doc__ = test_data_docstring + else: + # Try to call format on the docstring + if func.__doc__: + try: + wrapper.__doc__ = func.__doc__.format(*args, **kwargs) + except (IndexError, KeyError): + # Maybe the user has added some of the formating strings + # unintentionally in the docstring. Do not raise an exception + # as it could be that user is not aware of the + # formating feature. + pass + return wrapper + + +def add_test(cls, test_name, test_docstring, func, *args, **kwargs): + """ + Add a test case to this class. + + The test will be based on an existing function but will give it a new + name. + + """ + setattr(cls, test_name, feed_data(func, test_name, test_docstring, + *args, **kwargs)) + + +def process_file_data(cls, name, func, file_attr): + """ + Process the parameter in the `file_data` decorator. + """ + cls_path = os.path.abspath(inspect.getsourcefile(cls)) + data_file_path = os.path.join(os.path.dirname(cls_path), file_attr) + + def create_error_func(message): # pylint: disable-msg=W0613 + def func(*args): + raise ValueError(message % file_attr) + return func + + # If file does not exist, provide an error function instead + if not os.path.exists(data_file_path): + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test(cls, test_name, test_docstring, + create_error_func("%s does not exist"), None) + return + + _is_yaml_file = data_file_path.endswith((".yml", ".yaml")) + + # Don't have YAML but want to use YAML file. + if _is_yaml_file and not _have_yaml: + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test( + cls, + test_name, + test_docstring, + create_error_func("%s is a YAML file, please install PyYAML"), + None + ) + return + + with codecs.open(data_file_path, 'r', 'utf-8') as f: + # Load the data from YAML or JSON + if _is_yaml_file: + data = yaml.safe_load(f) + else: + data = json.load(f) + + _add_tests_from_data(cls, name, func, data) + + +def _add_tests_from_data(cls, name, func, data): + """ + Add tests from data loaded from the data file into the class + """ + for i, elem in enumerate(data): + if isinstance(data, dict): + key, value = elem, data[elem] + test_name = mk_test_name(name, key, i) + elif isinstance(data, list): + value = elem + test_name = mk_test_name(name, value, i) + if isinstance(value, dict): + add_test(cls, test_name, test_name, func, **value) + else: + add_test(cls, test_name, test_name, func, value) + + +def _is_primitive(obj): + """Finds out if the obj is a "primitive". It is somewhat hacky but it works. + """ + return not hasattr(obj, '__dict__') + + +def _get_test_data_docstring(func, value): + """Returns a docstring based on the following resolution strategy: + 1. Passed value is not a "primitive" and has a docstring, then use it. + 2. In all other cases return None, i.e the test name is used. + """ + if not _is_primitive(value) and value.__doc__: + return value.__doc__ + else: + return None + + +def ddt(cls): + """ + Class decorator for subclasses of ``unittest.TestCase``. + + Apply this decorator to the test case class, and then + decorate test methods with ``@data``. + + For each method decorated with ``@data``, this will effectively create as + many methods as data items are passed as parameters to ``@data``. + + The names of the test methods follow the pattern + ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the + data argument, starting with 1. + + For data we use a string representation of the data value converted into a + valid python identifier. If ``data.__name__`` exists, we use that instead. + + For each method decorated with ``@file_data('test_data.json')``, the + decorator will try to load the test_data.json file located relative + to the python file containing the method that is decorated. It will, + for each ``test_name`` key create as many methods in the list of values + from the ``data`` key. + + """ + for name, func in list(cls.__dict__.items()): + if hasattr(func, DATA_ATTR): + for i, v in enumerate(getattr(func, DATA_ATTR)): + test_name = mk_test_name(name, getattr(v, "__name__", v), i) + # 将用例描述信息改为用例数据的title字段 + # 原代码:test_data_docstring = _get_test_data_docstring(func, v) + test_data_docstring = v['title'] + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) + else: + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/login.py b/python27Class/homeWork/unitTest/homeWork03072020/demo1/login.py new file mode 100644 index 0000000..e89c145 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo1/login.py @@ -0,0 +1,21 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:42 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +def login_check(username=None, passwd=None): + """ + 登录校验的函数 + :param username: + :param passwd: + :return: dict type + """ + if username != None and passwd != None: + if username == 'flora' and passwd == '1234567Az': + return {'code': 0, 'msg': '登录成功'} + else: + return {'code': 1, 'msg': '账号或者密码不正确'} + else: + return {'code': 1, 'msg': '账号和密码不能为空'} \ No newline at end of file diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/readExcel.py b/python27Class/homeWork/unitTest/homeWork03072020/demo1/readExcel.py new file mode 100644 index 0000000..e2b556e --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo1/readExcel.py @@ -0,0 +1,59 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 18:58 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl +import os + + +# 从excel表格中读取数据 +def login_data(): + # 获取excel的路径 + data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'casesData.xlsx') + + # 将指定的excel文件加载为一个workbook对象 + work_book = openpyxl.load_workbook(data_path) + + # 选中工作簿中的表单对象 + sheet_name = work_book['casesData'] + + # 按行读取表格中所有数据 + excel_data = list(sheet_name.rows) + + # 定义两个空列表来接收数据 + data_key = [] + data_value = [] + + # 定义一个列表来接收用例数据 + cases_data = [] + + is_first_line = True + + + for line in excel_data: + # 如果是第一行数据,就将每个单元格数据追加到列表data_key中 + if is_first_line: + is_first_line = False + for column in line: + data_key.append(column.value) + continue + # 将剩余行数据中每个单元格数据追加到列表data_value中 + i = 0 + for column in line: + i += 1 + # 如果是第2列,则先获取单元格中的有效表达式(字典),再追加到data_value中 + if i == 2: + data_value.append(eval(column.value)) + continue + # 其他列,直接追加到列表data_value中 + data_value.append(column.value) + + # 将两个列表打包成字典追加到保存用例数据的列表中 + cases_data.append(dict(zip(data_key, data_value))) + # 清空列表data_value中的值,否则每次打包的数据都会是相同的数据 + data_value.clear() + return cases_data + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/runTest.py b/python27Class/homeWork/unitTest/homeWork03072020/demo1/runTest.py new file mode 100644 index 0000000..af2d73d --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo1/runTest.py @@ -0,0 +1,87 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 21:11 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +import unittest +import os + + +""" +第一步:创建测试套件 +""" +# suite = unittest.TestSuite() +""" +第二步:加载测试用例到测试套件 +""" +# 第一种:通过测试用例类去加载 +# from python27Class.homeWork.unitTest.homeWork03072020.testLogin import LoginTestCase +# loader = unittest.TestLoader() +# suite.addTest(loader.loadTestsFromTestCase(LoginTestCase)) + + +# 第二种:通过测试用例模块去加载 +# 用例加载器对象 +# from python27Class.homeWork.unitTest.homeWork03072020 import testLogin +# loader=unittest.TestLoader() +# suite.addTest(loader.loadTestsFromModule(testLogin)) + +# 第三种:通过路径去加载所有的测试用例 (推荐这一种) +# 注意:默认去找指定路径中test开头的模块中的测试用例 +# path = os.path.dirname(os.path.abspath(__file__)) +# loader = unittest.TestLoader() +# suite.addTest(loader.discover(path)) + +# 第四种:一条条去加载 +# from python27Class.homeWork.unitTest.homeWork03072020.testLogin import LoginTestCase +# case1 = LoginTestCase('test_login') +# suite.addTest(case1) +# # 报错: AttributeError: 'LoginTestCase' object has no attribute 'test_login' + +""" +综合第一步和第二步:创建套件并加载用例 +""" +path = os.path.dirname(os.path.abspath(__file__)) +suite = unittest.defaultTestLoader.discover(path) + +""" +第三步:(1)执行测试套件中的用例, 控制台生成报告 +""" +# 仅执行,未生成测试报告 +# 创建测试运行程序 +# runner = unittest.TextTestRunner() +# runner.run(suite) + +# ---------------------------------------------- +# 执行并生成测试报告 +""" +第三步:(2)使用BeautifulReport来执行测试套件中的用例并生成报告 +# 2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" +# from BeautifulReport import BeautifulReport +# beauty_report = BeautifulReport(suite) +# report_path = os.path.join(path, 'testReport') +# beauty_report.report('Login Function Test Report by flora', +# 'login_test_report_Beauty.html', +# report_dir=report_path) + + +# ---------------------------------------------- +""" +第三步:(3)使用HTMLTestRunner来生成测试报告 +stream表示报告存放的位置以及写入的模式 +title表示报告的标题 +tester表示测试人员 +description表示对测试报告的描述 +""" +from HTMLTestRunner import HTMLTestRunner +report_path = os.path.join(path, 'testReport') +runner = HTMLTestRunner(stream=open(os.path.join(report_path, 'login_test_report_HTML.html'), 'wb'), + title='Login Function Test Report', + tester='flora.chen', + description='Version 1.0') +runner.run(suite) diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo1/testLogin.py b/python27Class/homeWork/unitTest/homeWork03072020/demo1/testLogin.py new file mode 100644 index 0000000..fe96cd7 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo1/testLogin.py @@ -0,0 +1,54 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:23 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest + +from python27Class.homeWork.unitTest.homeWork03072020.demo1.login import login_check + +from python27Class.homeWork.unitTest.homeWork03072020.demo1.readExcel import login_data +from python27Class.homeWork.unitTest.homeWork03072020.demo1.ddtNew import ddt, data + +""" +# 定义测试用例类:必须继承unittest.TestCase +# 定义测试用例:在测试用例类中,每一个以test开头的方法就是一条用例 +# unittest中测试用例执行的顺序,是根据方法名按ASCII码进行排序的 +# unittest中会自动根据用例方法执行的时候,是否出现断言异常来评判用例执行是否通过 +""" + +@ddt +class LoginTestCase(unittest.TestCase): + # 第一步:准备用例数据 + # 第二步:获取实际结果(调用功能函数,传入参数,获取实际结果) + # 第三步:断言(比对预期结果和实际结果) + + # 方式一:直接定义列表作为测试数据 + # cases_data = [ + # {'title': '登录成功', 'expect_result': {'code': 0, 'msg': '登录成功'}, 'data': {'username': 'flora', 'passwd': '1234567Az'}}, + # {'title': '账号不正确', 'expect_result': {"code": 1, "msg": "账号或者密码不正确"}, 'data': {'username': 'flora.chen', 'passwd': '1234567Az'}}, + # {'title': '密码不正确', 'expect_result': {"code": 1, "msg": "账号或者密码不正确"}, 'data': {'username': 'flora', 'passwd': '1234567'}}, + # {'title': '账号为空', 'expect_result': {"code": 1, "msg": "账号和密码不能为空"},'data': {'passwd': '1234567Az'}}, + # {'title': '密码为空', 'expect_result': {"code": 1, "msg": "账号和密码不能为空"},'data': {'username': 'flora'}}, + # ] + + # 这里使用方式二:从excel中读取用例数据 + @data(*login_data()) + def test_login_case(self, case_data): + # 预期结果准备 + expect_result = case_data['expect_result'] + # 获取实际结果 + actual_result = login_check(case_data['username'], case_data['passwd']) + # 断言 + self.assertEqual(expect_result, actual_result) + + +if __name__ == '__main__': + login_test = LoginTestCase() + login_test.test_login_case(*login_test.cases_data) + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/casesData2.xlsx b/python27Class/homeWork/unitTest/homeWork03072020/demo2/casesData2.xlsx new file mode 100644 index 0000000..9742a84 Binary files /dev/null and b/python27Class/homeWork/unitTest/homeWork03072020/demo2/casesData2.xlsx differ diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/ddtNew.py b/python27Class/homeWork/unitTest/homeWork03072020/demo2/ddtNew.py new file mode 100644 index 0000000..2915330 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo2/ddtNew.py @@ -0,0 +1,319 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 10:52 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +# -*- coding: utf-8 -*- +# This file is a part of DDT (https://github.com/datadriventests/ddt) +# Copyright 2012-2015 Carles Barrobés and DDT contributors +# For the exact contribution history, see the git revision log. +# DDT is licensed under the MIT License, included in +# https://github.com/datadriventests/ddt/blob/master/LICENSE.md + +import inspect +import json +import os +import re +import codecs +from functools import wraps + +try: + import yaml +except ImportError: # pragma: no cover + _have_yaml = False +else: + _have_yaml = True + +__version__ = '1.2.2' + +# These attributes will not conflict with any real python attribute +# They are added to the decorated test method and processed later +# by the `ddt` class decorator. + +DATA_ATTR = '%values' # store the data the test must run with +FILE_ATTR = '%file_path' # store the path to JSON file +UNPACK_ATTR = '%unpack' # remember that we have to unpack values +index_len = 5 # default max length of case index + + +try: + trivial_types = (type(None), bool, int, float, basestring) +except NameError: + trivial_types = (type(None), bool, int, float, str) + + +def is_trivial(value): + if isinstance(value, trivial_types): + return True + elif isinstance(value, (list, tuple)): + return all(map(is_trivial, value)) + return False + + +def unpack(func): + """ + Method decorator to add unpack feature. + + """ + setattr(func, UNPACK_ATTR, True) + return func + + +def data(*values): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + global index_len + index_len = len(str(len(values))) + return idata(values) + + +def idata(iterable): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + def wrapper(func): + setattr(func, DATA_ATTR, iterable) + return func + return wrapper + + +def file_data(value): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + ``value`` should be a path relative to the directory of the file + containing the decorated ``unittest.TestCase``. The file + should contain JSON encoded data, that can either be a list or a + dict. + + In case of a list, each value in the list will correspond to one + test case, and the value will be concatenated to the test method + name. + + In case of a dict, keys will be used as suffixes to the name of the + test case, and values will be fed as test data. + + """ + def wrapper(func): + setattr(func, FILE_ATTR, value) + return func + return wrapper + + +def mk_test_name(name, value, index=0): + """ + Generate a new name for a test case. + + It will take the original test name and append an ordinal index and a + string representation of the value, and convert the result into a valid + python identifier by replacing extraneous characters with ``_``. + + We avoid doing str(value) if dealing with non-trivial values. + The problem is possible different names with different runs, e.g. + different order of dictionary keys (see PYTHONHASHSEED) or dealing + with mock objects. + Trivial scalar values are passed as is. + + A "trivial" value is a plain scalar, or a tuple or list consisting + only of trivial values. + """ + + # Add zeros before index to keep order + index = "{0:0{1}}".format(index + 1, index_len) + if not is_trivial(value): + return "{0}_{1}".format(name, index) + try: + value = str(value) + except UnicodeEncodeError: + # fallback for python2 + value = value.encode('ascii', 'backslashreplace') + test_name = "{0}_{1}_{2}".format(name, index, value) + return re.sub(r'\W|^(?=\d)', '_', test_name) + + +def feed_data(func, new_name, test_data_docstring, *args, **kwargs): + """ + This internal method decorator feeds the test data item to the test. + + """ + @wraps(func) + def wrapper(self): + return func(self, *args, **kwargs) + wrapper.__name__ = new_name + wrapper.__wrapped__ = func + # set docstring if exists + if test_data_docstring is not None: + wrapper.__doc__ = test_data_docstring + else: + # Try to call format on the docstring + if func.__doc__: + try: + wrapper.__doc__ = func.__doc__.format(*args, **kwargs) + except (IndexError, KeyError): + # Maybe the user has added some of the formating strings + # unintentionally in the docstring. Do not raise an exception + # as it could be that user is not aware of the + # formating feature. + pass + return wrapper + + +def add_test(cls, test_name, test_docstring, func, *args, **kwargs): + """ + Add a test case to this class. + + The test will be based on an existing function but will give it a new + name. + + """ + setattr(cls, test_name, feed_data(func, test_name, test_docstring, + *args, **kwargs)) + + +def process_file_data(cls, name, func, file_attr): + """ + Process the parameter in the `file_data` decorator. + """ + cls_path = os.path.abspath(inspect.getsourcefile(cls)) + data_file_path = os.path.join(os.path.dirname(cls_path), file_attr) + + def create_error_func(message): # pylint: disable-msg=W0613 + def func(*args): + raise ValueError(message % file_attr) + return func + + # If file does not exist, provide an error function instead + if not os.path.exists(data_file_path): + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test(cls, test_name, test_docstring, + create_error_func("%s does not exist"), None) + return + + _is_yaml_file = data_file_path.endswith((".yml", ".yaml")) + + # Don't have YAML but want to use YAML file. + if _is_yaml_file and not _have_yaml: + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test( + cls, + test_name, + test_docstring, + create_error_func("%s is a YAML file, please install PyYAML"), + None + ) + return + + with codecs.open(data_file_path, 'r', 'utf-8') as f: + # Load the data from YAML or JSON + if _is_yaml_file: + data = yaml.safe_load(f) + else: + data = json.load(f) + + _add_tests_from_data(cls, name, func, data) + + +def _add_tests_from_data(cls, name, func, data): + """ + Add tests from data loaded from the data file into the class + """ + for i, elem in enumerate(data): + if isinstance(data, dict): + key, value = elem, data[elem] + test_name = mk_test_name(name, key, i) + elif isinstance(data, list): + value = elem + test_name = mk_test_name(name, value, i) + if isinstance(value, dict): + add_test(cls, test_name, test_name, func, **value) + else: + add_test(cls, test_name, test_name, func, value) + + +def _is_primitive(obj): + """Finds out if the obj is a "primitive". It is somewhat hacky but it works. + """ + return not hasattr(obj, '__dict__') + + +def _get_test_data_docstring(func, value): + """Returns a docstring based on the following resolution strategy: + 1. Passed value is not a "primitive" and has a docstring, then use it. + 2. In all other cases return None, i.e the test name is used. + """ + if not _is_primitive(value) and value.__doc__: + return value.__doc__ + else: + return None + + +def ddt(cls): + """ + Class decorator for subclasses of ``unittest.TestCase``. + + Apply this decorator to the test case class, and then + decorate test methods with ``@data``. + + For each method decorated with ``@data``, this will effectively create as + many methods as data items are passed as parameters to ``@data``. + + The names of the test methods follow the pattern + ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the + data argument, starting with 1. + + For data we use a string representation of the data value converted into a + valid python identifier. If ``data.__name__`` exists, we use that instead. + + For each method decorated with ``@file_data('test_data.json')``, the + decorator will try to load the test_data.json file located relative + to the python file containing the method that is decorated. It will, + for each ``test_name`` key create as many methods in the list of values + from the ``data`` key. + + """ + for name, func in list(cls.__dict__.items()): + if hasattr(func, DATA_ATTR): + for i, v in enumerate(getattr(func, DATA_ATTR)): + test_name = mk_test_name(name, getattr(v, "__name__", v), i) + # 将用例描述信息改为用例数据的title字段 + # 原代码:test_data_docstring = _get_test_data_docstring(func, v) + test_data_docstring = v['title'] + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) + else: + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/login.py b/python27Class/homeWork/unitTest/homeWork03072020/demo2/login.py new file mode 100644 index 0000000..e89c145 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo2/login.py @@ -0,0 +1,21 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:42 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +def login_check(username=None, passwd=None): + """ + 登录校验的函数 + :param username: + :param passwd: + :return: dict type + """ + if username != None and passwd != None: + if username == 'flora' and passwd == '1234567Az': + return {'code': 0, 'msg': '登录成功'} + else: + return {'code': 1, 'msg': '账号或者密码不正确'} + else: + return {'code': 1, 'msg': '账号和密码不能为空'} \ No newline at end of file diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/readExcel2.py b/python27Class/homeWork/unitTest/homeWork03072020/demo2/readExcel2.py new file mode 100644 index 0000000..2e7f400 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo2/readExcel2.py @@ -0,0 +1,59 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 18:58 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl +import os + + +# 从excel表格中读取数据 +def login_data(): + # 获取excel的路径 + data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'casesData2.xlsx') + + # 将指定的excel文件加载为一个workbook对象 + work_book = openpyxl.load_workbook(data_path) + + # 选中工作簿中的表单对象 + sheet_name = work_book['casesData'] + + # 按行读取表格中所有数据 + excel_data = list(sheet_name.rows) + + # 定义两个空列表来接收数据 + data_key = [] + data_value = [] + + # 定义一个列表来接收用例数据 + cases_data = [] + + is_first_line = True + + + for line in excel_data: + # 如果是第一行数据,就将每个单元格数据追加到列表data_key中 + if is_first_line: + is_first_line = False + for column in line: + data_key.append(column.value) + continue + # 将剩余行数据中每个单元格数据追加到列表data_value中 + is_first_column = True + for column in line: + # 如果是第一列,则直接追加到列表data_value中 + if is_first_column: + data_value.append(column.value) + is_first_column = False + continue + # 如果是剩余列,则先获取单元格中的有效表达式(字典),再追加到data_value中 + data_value.append(eval(column.value)) + + # 将两个列表打包成字典追加到保存用例数据的列表中 + cases_data.append(dict(zip(data_key, data_value))) + # 清空列表data_value中的值,否则每次打包的数据都会是相同的数据 + data_value.clear() + return cases_data + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/runTest.py b/python27Class/homeWork/unitTest/homeWork03072020/demo2/runTest.py new file mode 100644 index 0000000..af2d73d --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo2/runTest.py @@ -0,0 +1,87 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 21:11 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +import unittest +import os + + +""" +第一步:创建测试套件 +""" +# suite = unittest.TestSuite() +""" +第二步:加载测试用例到测试套件 +""" +# 第一种:通过测试用例类去加载 +# from python27Class.homeWork.unitTest.homeWork03072020.testLogin import LoginTestCase +# loader = unittest.TestLoader() +# suite.addTest(loader.loadTestsFromTestCase(LoginTestCase)) + + +# 第二种:通过测试用例模块去加载 +# 用例加载器对象 +# from python27Class.homeWork.unitTest.homeWork03072020 import testLogin +# loader=unittest.TestLoader() +# suite.addTest(loader.loadTestsFromModule(testLogin)) + +# 第三种:通过路径去加载所有的测试用例 (推荐这一种) +# 注意:默认去找指定路径中test开头的模块中的测试用例 +# path = os.path.dirname(os.path.abspath(__file__)) +# loader = unittest.TestLoader() +# suite.addTest(loader.discover(path)) + +# 第四种:一条条去加载 +# from python27Class.homeWork.unitTest.homeWork03072020.testLogin import LoginTestCase +# case1 = LoginTestCase('test_login') +# suite.addTest(case1) +# # 报错: AttributeError: 'LoginTestCase' object has no attribute 'test_login' + +""" +综合第一步和第二步:创建套件并加载用例 +""" +path = os.path.dirname(os.path.abspath(__file__)) +suite = unittest.defaultTestLoader.discover(path) + +""" +第三步:(1)执行测试套件中的用例, 控制台生成报告 +""" +# 仅执行,未生成测试报告 +# 创建测试运行程序 +# runner = unittest.TextTestRunner() +# runner.run(suite) + +# ---------------------------------------------- +# 执行并生成测试报告 +""" +第三步:(2)使用BeautifulReport来执行测试套件中的用例并生成报告 +# 2个参数:报告描述(用例名称),报告文件名 +report_dir:用来指定报告的存放位置 +""" +# from BeautifulReport import BeautifulReport +# beauty_report = BeautifulReport(suite) +# report_path = os.path.join(path, 'testReport') +# beauty_report.report('Login Function Test Report by flora', +# 'login_test_report_Beauty.html', +# report_dir=report_path) + + +# ---------------------------------------------- +""" +第三步:(3)使用HTMLTestRunner来生成测试报告 +stream表示报告存放的位置以及写入的模式 +title表示报告的标题 +tester表示测试人员 +description表示对测试报告的描述 +""" +from HTMLTestRunner import HTMLTestRunner +report_path = os.path.join(path, 'testReport') +runner = HTMLTestRunner(stream=open(os.path.join(report_path, 'login_test_report_HTML.html'), 'wb'), + title='Login Function Test Report', + tester='flora.chen', + description='Version 1.0') +runner.run(suite) diff --git a/python27Class/homeWork/unitTest/homeWork03072020/demo2/testLogin2.py b/python27Class/homeWork/unitTest/homeWork03072020/demo2/testLogin2.py new file mode 100644 index 0000000..e9796be --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/demo2/testLogin2.py @@ -0,0 +1,54 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:23 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import unittest +from python27Class.homeWork.unitTest.homeWork03072020.demo2.ddtNew import ddt, data +from python27Class.homeWork.unitTest.homeWork03072020.demo2.login import login_check +from python27Class.homeWork.unitTest.homeWork03072020.demo2.readExcel2 import login_data + +""" +# 定义测试用例类:必须继承unittest.TestCase +# 定义测试用例:在测试用例类中,每一个以test开头的方法就是一条用例 +# unittest中测试用例执行的顺序,是根据方法名按ASCII码进行排序的 +# unittest中会自动根据用例方法执行的时候,是否出现断言异常来评判用例执行是否通过 +""" + +@ddt +class LoginTestCase(unittest.TestCase): + # 第一步:准备用例数据 + # 第二步:获取实际结果(调用功能函数,传入参数,获取实际结果) + # 第三步:断言(比对预期结果和实际结果) + + # 方式一:直接定义列表作为测试数据 + # cases_data = [ + # {'title': '登录成功', 'expect_result': {'code': 0, 'msg': '登录成功'}, 'data': {'username': 'flora', 'passwd': '1234567Az'}}, + # {'title': '账号不正确', 'expect_result': {"code": 1, "msg": "账号或者密码不正确"}, 'data': {'username': 'flora.chen', 'passwd': '1234567Az'}}, + # {'title': '密码不正确', 'expect_result': {"code": 1, "msg": "账号或者密码不正确"}, 'data': {'username': 'flora', 'passwd': '1234567'}}, + # {'title': '账号为空', 'expect_result': {"code": 1, "msg": "账号和密码不能为空"},'data': {'passwd': '1234567Az'}}, + # {'title': '密码为空', 'expect_result': {"code": 1, "msg": "账号和密码不能为空"},'data': {'username': 'flora'}}, + # ] + + # 这里使用方式二:从excel中读取用例数据 + @data(*login_data()) + def test_login_case(self, case_data): + # 参数准备 + login_data = case_data['data'] + # 预期结果准备 + expect_result = case_data['expect_result'] + # 获取实际结果 + actual_result = login_check(**login_data) + # 断言 + self.assertEqual(expect_result, actual_result) + + + +if __name__ == '__main__': + login_test = LoginTestCase() + login_test.test_login_case(*login_test.cases_data) + + + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_Beauty.html b/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_Beauty.html new file mode 100644 index 0000000..7444846 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_Beauty.html @@ -0,0 +1,7390 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_HTML.html b/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_HTML.html new file mode 100644 index 0000000..9bc8c04 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03072020/testReport/login_test_report_HTML.html @@ -0,0 +1,235 @@ + + + + + Login Function Test Report + + + + + + + + + + + +
+

Login Function Test Report

+

测试人员 : flora.chen

+

开始时间 : 2020-03-07 20:11:50

+

合计耗时 : 0:00:00

+

测试结果 : 共 10,通过 10,通过率= 100.00%

+ +

Version 1.0

+
+ + +

+概要{ 100.00% } +失败{ 0 } +通过{ 10 } +所有{ 10 } +

+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
用例集/测试用例总计通过失败错误详细
testLogin.LoginTestCase5500详细
test_login_1: 登录成功
通过
test_login_2: 账号不正确
通过
test_login_3: 密码不正确
通过
test_login_4: 账号为空
通过
test_login_5: 密码为空
通过
testLogin2.LoginTestCase5500详细
test_login_1: 登录成功
通过
test_login_2: 账号不正确
通过
test_login_3: 密码不正确
通过
test_login_4: 账号为空
通过
test_login_5: 密码为空
通过
总计101000通过率:100.00%
+ +
 
+
+
+ + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/ddtNew.py b/python27Class/homeWork/unitTest/homeWork03102020/ddtNew.py new file mode 100644 index 0000000..2915330 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/ddtNew.py @@ -0,0 +1,319 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/7 10:52 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +# -*- coding: utf-8 -*- +# This file is a part of DDT (https://github.com/datadriventests/ddt) +# Copyright 2012-2015 Carles Barrobés and DDT contributors +# For the exact contribution history, see the git revision log. +# DDT is licensed under the MIT License, included in +# https://github.com/datadriventests/ddt/blob/master/LICENSE.md + +import inspect +import json +import os +import re +import codecs +from functools import wraps + +try: + import yaml +except ImportError: # pragma: no cover + _have_yaml = False +else: + _have_yaml = True + +__version__ = '1.2.2' + +# These attributes will not conflict with any real python attribute +# They are added to the decorated test method and processed later +# by the `ddt` class decorator. + +DATA_ATTR = '%values' # store the data the test must run with +FILE_ATTR = '%file_path' # store the path to JSON file +UNPACK_ATTR = '%unpack' # remember that we have to unpack values +index_len = 5 # default max length of case index + + +try: + trivial_types = (type(None), bool, int, float, basestring) +except NameError: + trivial_types = (type(None), bool, int, float, str) + + +def is_trivial(value): + if isinstance(value, trivial_types): + return True + elif isinstance(value, (list, tuple)): + return all(map(is_trivial, value)) + return False + + +def unpack(func): + """ + Method decorator to add unpack feature. + + """ + setattr(func, UNPACK_ATTR, True) + return func + + +def data(*values): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + global index_len + index_len = len(str(len(values))) + return idata(values) + + +def idata(iterable): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + """ + def wrapper(func): + setattr(func, DATA_ATTR, iterable) + return func + return wrapper + + +def file_data(value): + """ + Method decorator to add to your test methods. + + Should be added to methods of instances of ``unittest.TestCase``. + + ``value`` should be a path relative to the directory of the file + containing the decorated ``unittest.TestCase``. The file + should contain JSON encoded data, that can either be a list or a + dict. + + In case of a list, each value in the list will correspond to one + test case, and the value will be concatenated to the test method + name. + + In case of a dict, keys will be used as suffixes to the name of the + test case, and values will be fed as test data. + + """ + def wrapper(func): + setattr(func, FILE_ATTR, value) + return func + return wrapper + + +def mk_test_name(name, value, index=0): + """ + Generate a new name for a test case. + + It will take the original test name and append an ordinal index and a + string representation of the value, and convert the result into a valid + python identifier by replacing extraneous characters with ``_``. + + We avoid doing str(value) if dealing with non-trivial values. + The problem is possible different names with different runs, e.g. + different order of dictionary keys (see PYTHONHASHSEED) or dealing + with mock objects. + Trivial scalar values are passed as is. + + A "trivial" value is a plain scalar, or a tuple or list consisting + only of trivial values. + """ + + # Add zeros before index to keep order + index = "{0:0{1}}".format(index + 1, index_len) + if not is_trivial(value): + return "{0}_{1}".format(name, index) + try: + value = str(value) + except UnicodeEncodeError: + # fallback for python2 + value = value.encode('ascii', 'backslashreplace') + test_name = "{0}_{1}_{2}".format(name, index, value) + return re.sub(r'\W|^(?=\d)', '_', test_name) + + +def feed_data(func, new_name, test_data_docstring, *args, **kwargs): + """ + This internal method decorator feeds the test data item to the test. + + """ + @wraps(func) + def wrapper(self): + return func(self, *args, **kwargs) + wrapper.__name__ = new_name + wrapper.__wrapped__ = func + # set docstring if exists + if test_data_docstring is not None: + wrapper.__doc__ = test_data_docstring + else: + # Try to call format on the docstring + if func.__doc__: + try: + wrapper.__doc__ = func.__doc__.format(*args, **kwargs) + except (IndexError, KeyError): + # Maybe the user has added some of the formating strings + # unintentionally in the docstring. Do not raise an exception + # as it could be that user is not aware of the + # formating feature. + pass + return wrapper + + +def add_test(cls, test_name, test_docstring, func, *args, **kwargs): + """ + Add a test case to this class. + + The test will be based on an existing function but will give it a new + name. + + """ + setattr(cls, test_name, feed_data(func, test_name, test_docstring, + *args, **kwargs)) + + +def process_file_data(cls, name, func, file_attr): + """ + Process the parameter in the `file_data` decorator. + """ + cls_path = os.path.abspath(inspect.getsourcefile(cls)) + data_file_path = os.path.join(os.path.dirname(cls_path), file_attr) + + def create_error_func(message): # pylint: disable-msg=W0613 + def func(*args): + raise ValueError(message % file_attr) + return func + + # If file does not exist, provide an error function instead + if not os.path.exists(data_file_path): + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test(cls, test_name, test_docstring, + create_error_func("%s does not exist"), None) + return + + _is_yaml_file = data_file_path.endswith((".yml", ".yaml")) + + # Don't have YAML but want to use YAML file. + if _is_yaml_file and not _have_yaml: + test_name = mk_test_name(name, "error") + test_docstring = """Error!""" + add_test( + cls, + test_name, + test_docstring, + create_error_func("%s is a YAML file, please install PyYAML"), + None + ) + return + + with codecs.open(data_file_path, 'r', 'utf-8') as f: + # Load the data from YAML or JSON + if _is_yaml_file: + data = yaml.safe_load(f) + else: + data = json.load(f) + + _add_tests_from_data(cls, name, func, data) + + +def _add_tests_from_data(cls, name, func, data): + """ + Add tests from data loaded from the data file into the class + """ + for i, elem in enumerate(data): + if isinstance(data, dict): + key, value = elem, data[elem] + test_name = mk_test_name(name, key, i) + elif isinstance(data, list): + value = elem + test_name = mk_test_name(name, value, i) + if isinstance(value, dict): + add_test(cls, test_name, test_name, func, **value) + else: + add_test(cls, test_name, test_name, func, value) + + +def _is_primitive(obj): + """Finds out if the obj is a "primitive". It is somewhat hacky but it works. + """ + return not hasattr(obj, '__dict__') + + +def _get_test_data_docstring(func, value): + """Returns a docstring based on the following resolution strategy: + 1. Passed value is not a "primitive" and has a docstring, then use it. + 2. In all other cases return None, i.e the test name is used. + """ + if not _is_primitive(value) and value.__doc__: + return value.__doc__ + else: + return None + + +def ddt(cls): + """ + Class decorator for subclasses of ``unittest.TestCase``. + + Apply this decorator to the test case class, and then + decorate test methods with ``@data``. + + For each method decorated with ``@data``, this will effectively create as + many methods as data items are passed as parameters to ``@data``. + + The names of the test methods follow the pattern + ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the + data argument, starting with 1. + + For data we use a string representation of the data value converted into a + valid python identifier. If ``data.__name__`` exists, we use that instead. + + For each method decorated with ``@file_data('test_data.json')``, the + decorator will try to load the test_data.json file located relative + to the python file containing the method that is decorated. It will, + for each ``test_name`` key create as many methods in the list of values + from the ``data`` key. + + """ + for name, func in list(cls.__dict__.items()): + if hasattr(func, DATA_ATTR): + for i, v in enumerate(getattr(func, DATA_ATTR)): + test_name = mk_test_name(name, getattr(v, "__name__", v), i) + # 将用例描述信息改为用例数据的title字段 + # 原代码:test_data_docstring = _get_test_data_docstring(func, v) + test_data_docstring = v['title'] + if hasattr(func, UNPACK_ATTR): + if isinstance(v, tuple) or isinstance(v, list): + add_test( + cls, + test_name, + test_data_docstring, + func, + *v + ) + else: + # unpack dictionary + add_test( + cls, + test_name, + test_data_docstring, + func, + **v + ) + else: + add_test(cls, test_name, test_data_docstring, func, v) + delattr(cls, name) + elif hasattr(func, FILE_ATTR): + file_attr = getattr(func, FILE_ATTR) + process_file_data(cls, name, func, file_attr) + delattr(cls, name) + return cls diff --git a/python27Class/homeWork/unitTest/homeWork03102020/login.py b/python27Class/homeWork/unitTest/homeWork03102020/login.py new file mode 100644 index 0000000..e89c145 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/login.py @@ -0,0 +1,21 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/5 20:42 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +def login_check(username=None, passwd=None): + """ + 登录校验的函数 + :param username: + :param passwd: + :return: dict type + """ + if username != None and passwd != None: + if username == 'flora' and passwd == '1234567Az': + return {'code': 0, 'msg': '登录成功'} + else: + return {'code': 1, 'msg': '账号或者密码不正确'} + else: + return {'code': 1, 'msg': '账号和密码不能为空'} \ No newline at end of file diff --git a/python27Class/homeWork/unitTest/homeWork03102020/loginCaseData.xlsx b/python27Class/homeWork/unitTest/homeWork03102020/loginCaseData.xlsx new file mode 100644 index 0000000..75b39cf Binary files /dev/null and b/python27Class/homeWork/unitTest/homeWork03102020/loginCaseData.xlsx differ diff --git a/python27Class/homeWork/unitTest/homeWork03102020/readExcel.py b/python27Class/homeWork/unitTest/homeWork03102020/readExcel.py new file mode 100644 index 0000000..f586e31 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/readExcel.py @@ -0,0 +1,79 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/11 9:08 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" +import openpyxl + +class HandleExcel: + """ + 这是一个从excel中读取用例数据并将测试结果写回excel的类 + """ + def __init__(self, filename, sheetname): + """ + 实例属性 + :param filename: excel文件的绝对路径 + :param sheetname: excel中我们需要读取的表单的名称 + """ + self.filename = filename + self.sheetname = sheetname + + def read_data(self): + # 获取工作簿对象 + wb = openpyxl.load_workbook(self.filename) + + # 获取该工作簿的表单 + sh = wb[self.sheetname] + + # 获取所有行的数据 + rows_data = list(sh.rows) + + # 定义一个空列表cases_data来保存所有的用例数据 + cases_data = [] + + # 获取表头,将表头每个单元格中的数据值保存在列表title中 + title = [] + for i in rows_data[0]: + title.append(i.value) + + # 获取剩余行的数据,并将剩余行每个单元格的数据值保存在列表values中 + for i in rows_data[1:]: + values = [] + for j in i: + values.append(j.value) + + # 将title跟每一行的values打包成字典并追加到cases_data列表中 + cases_data.append(dict(zip(title, values))) + + # 关闭保存excel文件 + wb.save(self.filename) + + # 将用例数据返回 + return cases_data + + def write_data(self, row, column, value): + """ + 执行完测试用例后将测试结果写回到excel的类 + :param row: 要写入的行 + :param column: 要写入的列 + :param value: 要写入的内容 + :return: + """ + # 获取工作簿对象 + wb = openpyxl.load_workbook(self.filename) + + # 获取该工作簿的表单 + sh = wb[self.sheetname] + + # 在指定行列写入数据 + sh.cell(row=row, column=column, value=value) + + # 关闭保存excel文件 + wb.save(self.filename) + +if __name__ == '__main__': + excel = HandleExcel('loginCaseData.xlsx', 'loginData') + print(excel.read_data()) + # excel.write_data(7, 5, 'flora') diff --git a/python27Class/homeWork/unitTest/homeWork03102020/runTest.py b/python27Class/homeWork/unitTest/homeWork03102020/runTest.py new file mode 100644 index 0000000..6cff529 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/runTest.py @@ -0,0 +1,49 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/11 9:46 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +import unittest +import os +import time +from BeautifulReport import BeautifulReport +from HTMLTestRunner import HTMLTestRunner + +# # 创建测试套件 +# suite = unittest.TestSuite() +# +# # 执行当前目录下所有的test开头的模块 +# loader = unittest.TestLoader() +# case_path = os.path.dirname(os.path.abspath(__file__)) +# suite.addTest(loader.discover(case_path)) + +# 创建并加载测试用例 +case_path = os.path.dirname(os.path.abspath(__file__)) +suite = unittest.defaultTestLoader.discover(case_path) + + +# 存放测试报告的路径 +report_path = os.path.join(case_path, 'testReport') + +# 获取当前时间 +now_time = time.strftime('%Y-%m-%d %H_%M_%S') + +# 定义测试报告的名称 +report_name = 'login_' + now_time + '.html' + +# # 使用BeautifulReport生成测试报告 +br = BeautifulReport(suite) +br.report('Login Function Test Report by flora', report_name, report_dir=report_path) + +# 使用HTMLTestRunner生成测试报告 +# result_html = open(os.path.join(report_path, report_name), 'wb') +# runner = HTMLTestRunner(stream=result_html, +# title='Login Function Test Report', +# tester='flora.chen', +# description='Version 2.0' +# ) +# runner.run(suite) +# result_html.close() \ No newline at end of file diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testLogin.py b/python27Class/homeWork/unitTest/homeWork03102020/testLogin.py new file mode 100644 index 0000000..db3515c --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testLogin.py @@ -0,0 +1,66 @@ +""" +================================= +Author: Flora Chen +Time: 2020/3/11 8:57 +-_- -_- -_- -_- -_- -_- -_- -_- +================================= +""" + +import os +import unittest +from python27Class.homeWork.unitTest.homeWork03102020.login import login_check +from python27Class.homeWork.unitTest.homeWork03102020.ddtNew import ddt, data +from python27Class.homeWork.unitTest.homeWork03102020.readExcel import HandleExcel + + +@ddt +class TestLoginCase(unittest.TestCase): + """ + 这是用来测试登录功能的类 + """ + # 实例化HandleExcel类 + excel_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'loginCaseData.xlsx') + excel = HandleExcel(excel_path, 'loginData') + # 调用HandleExcel类中的read_data()方法 + cases_data = excel.read_data() + + @data(*cases_data) + def test_login_case(self, case_data): + """ + 这是用来测试登录功能的用例 + :param case_data: 用例数据 + :return: + """ + # 首先准备用例数据 + login_data = eval(case_data['login_data']) + expect_result = eval(case_data['expect_result']) + + # 调用login获取实际结果 + actual_result = login_check(**login_data) + + # 要写入的行 + row = case_data['case_id'] + 1 + + # 要写入的列,默认是excel用例数据的最后一列(result列)。 + column = len(case_data) + + # 定义一个变量来接收测试结果 + test_result = '' + + # 捕获异常,不管用例是通过还是未通过,最终都将测试结果写入excel中 + try: + self.assertEqual(expect_result, actual_result) + # 如果用例失败,将未通过写回excel并抛出异常 + except AssertionError as e: + test_result = '未通过' + raise e + # 如果用例通过,将通过写回excel + else: + test_result = '通过' + finally: + self.excel.write_data(row=row, column=column, value=test_result) + + + +if __name__ == '__main__': + unittest.main() diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/loginFunctionTestReport_01.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/loginFunctionTestReport_01.html new file mode 100644 index 0000000..9b8f034 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/loginFunctionTestReport_01.html @@ -0,0 +1,7390 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_06.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_06.html new file mode 100644 index 0000000..9d4fe49 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_06.html @@ -0,0 +1,238 @@ + + + + + Login Function Test Report + + + + + + + + + + + +
+

Login Function Test Report

+

测试人员 : flora.chen

+

开始时间 : 2020-03-11 14:06:06

+

合计耗时 : 0:00:00.112031

+

测试结果 : 共 7,通过 6,失败 1,通过率= 85.71%

+ +

Version 2.0

+
+ + +

+概要{ 85.71% } +失败{ 1 } +通过{ 6 } +所有{ 7 } +

+ ++++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
用例集/测试用例总计通过失败错误详细
testLogin.TestLoginCase7610详细
test_login_case_1: 登录成功
通过
test_login_case_2: 账号不正确
通过
test_login_case_3: 密码不正确
通过
test_login_case_4: 账号为空
通过
test_login_case_5: 密码为空
通过
test_login_case_6: 账号和密码都为空
通过
test_login_case_7: 失败的用例
+ + + +
+
+    
+ft1_7: Traceback (most recent call last):
+  File "E:\PycharmProject\ChyClass\python27Class\homeWork\unitTest\homeWork03102020\ddtNew.py", line 152, in wrapper
+    return func(self, *args, **kwargs)
+  File "E:\PycharmProject\ChyClass\python27Class\homeWork\unitTest\homeWork03102020\testLogin.py", line 53, in test_login_case
+    raise e
+  File "E:\PycharmProject\ChyClass\python27Class\homeWork\unitTest\homeWork03102020\testLogin.py", line 49, in test_login_case
+    self.assertEqual(expect_result, actual_result)
+AssertionError: {'code': 2, 'msg': '账号和密码不能为空'} != {'code': 1, 'msg': '账号和密码不能为空'}
+- {'code': 2, 'msg': '账号和密码不能为空'}
+?          ^
+
++ {'code': 1, 'msg': '账号和密码不能为空'}
+?          ^
+
+
+
+    
+
+
总计7610通过率:85.71%
+ +
 
+
+
+ + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_52.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_52.html new file mode 100644 index 0000000..2adf0b3 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_06_52.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_21.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_21.html new file mode 100644 index 0000000..28c8821 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_21.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_43.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_43.html new file mode 100644 index 0000000..f12ce59 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-11 14_20_43.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_28.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_28.html new file mode 100644 index 0000000..d353c9b --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_28.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_54.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_54.html new file mode 100644 index 0000000..05ff60b --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_12_54.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_20.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_20.html new file mode 100644 index 0000000..c48b6bf --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_20.html @@ -0,0 +1,7356 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + + diff --git a/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_30.html b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_30.html new file mode 100644 index 0000000..3ff57f9 --- /dev/null +++ b/python27Class/homeWork/unitTest/homeWork03102020/testReport/login_2020-03-12 12_15_30.html @@ -0,0 +1,7421 @@ + + + + + 测试报告 + + + + + + + + +
+
+ 测试报告 +
+
+
+
+
+
+
+
报告汇总
+ +
+
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
详细数据
+ +
+
+
+ + + + +
+ +
+
+ + + + + + + + + + + + + + +
编号测试类测试方法用例描述运行时长结果操作
+
+
+
+
+
+ + + + + + +