输入输出的设备主要有键盘、屏幕、网卡、文件等。

7.1 键盘和屏幕

  • input

    • 接收键盘的输入,得到的是字符串,name = input('your name:'),要想的到数字,需要进行类型转换
  • print

    • 输出到屏幕,print(“Hello world”)

7.2 文件路径

对文件系统的访问,大多通过Python的os模块实现。该模块是Python访问文件系统功能的主要接口。

通过下面代码可以查看os模块的全部功能。

>>> import os
>>> dir(os)

例如,获取当前工作目录:

import os
print(os.getcwd())

设置和读取环境变量:

import osos.environ['WORKON_HOME'] = "value"   # 设置环境变量
print(os.getenv('WORKON_HOME'))  # 读取环境变量

创建目录,或者多层目录

import ospath = "/Users/chunming.liu/learn"
if not os.path.exists(path):os.mkdir(path, 777)  # 如果是创建多层目录,则使用os.mkdirs
else:print("Already exists")

文件路径的操作是工程中经常遇到的。对文件路径的操作是通过os.path模块实现的。可以通过help(os.path)查看所有方法的使用方法。

>>> path = '/Users/chunming.liu/learn/learn_python_by_coding/learn_string/learn_str.py'
>>> os.path.basename(path)  # 获取文件名
'learn_str.py'
>>> os.path.dirname(path)  # 获取目录名
'/Users/chunming.liu/learn/learn_python_by_coding/learn_string'
>>> os.path.split(path)  # 获取目录名和文件名
('/Users/chunming.liu/learn/learn_python_by_coding/learn_string', 'learn_str.py')
>>> os.path.splitext(path)  #获取扩展名
('/Users/chunming.liu/learn/learn_python_by_coding/learn_string/learn_str', '.py')
>>> os.path.join("/Users/chunming.liu","learn/learn_python_by_coding/","learn_str.py") # 拼接
'/Users/chunming.liu/learn/learn_python_by_coding/learn_str.py'

通常实际工程中,会遇到求当前py文件所在的路径,这时path是__file__

import os
print(os.path.realpath(__file__))  # 如果是符号链接,则返回符号链接指向的文件绝对路径
print(os.path.abspath(__file__))  # 文件绝对路径
print(os.path.basename(os.path.abspath(__file__)))  #当前py文件名
print(os.path.dirname(os.path.dirname(__file__)))  # 当前文件名的上上级目录

案例应用,查找某个目录下特定扩展名的所有文件名,返回列表。

import osdef find_ext(work_dir, extension):lst = []for f in os.listdir(work_dir):ext = os.path.splitext(f)[1]if ext == extension:lst.append(os.path.basename(f))return lstif __name__ == '__main__':print(find_ext(os.path.dirname(__file__), '.txt'))

7.3 文件读写

open函数用于打开一个文件。

7.3.1 读取整个文件

import osdef read_file(filename):content = Noneif os.path.exists(filename):  # 判断文件存在with open(filename) as f:content = f.read()  # 一次读取整个文件return contentif __name__ == '__main__':print(read_file(__file__))  # 读取当前py文件内容^.^

7.3.2 一行一行读取

read 函数一次读取整个文件,readlines 函数按行一次读取整个文件。读入文件小时,使用它们没有问题。

但是,如果读入文件大,read 或 readlines 一次读取整个文件,内存就会面临重大挑战。

使用 readline 一次读取文件一行,读入一行处理一行,能解决大文件读取内存溢出问题。

假设文件 python.txt 内容如下,请你统计单词出现频次,按照频次从大到小降序:

Python 3.8.3 documentation
Welcome!          This is the documentation for Python 3.8.3.Parts of the documentation:What's new in Python 3.8?
or all "What's new" documents since 2.0

思路及步骤:

  1. 每次读入一行。
  2. 选择正则 split 分词,注意观察 a.txt,单词间有的一个空格,有的多个。这些情况,实际工作中确实也会遇到。
  3. 使用 defaultdict 统计单词出现频次。
  4. 按照频次从大到小降序。
import re
from collections import defaultdictword_count = defaultdict(int)  # 声明一个int值型的默认字典
with open('python.txt') as f:for line in f:  # 哇哈,f可以迭代,一次取一行处理clean_line = line.strip()if clean_line:sp = re.compile(r'\s+')  # 多个空格words = sp.split(clean_line)   # 正则分词for w in words:word_count[w] += 1  # 默认字典的好处sorted(word_count.items(), key=lambda x: x[1], reverse=True)  # 排序,哇哦
print(word_count)  # defaultdict(<class 'int'>, {'Python': 3, '3.8.3': 1, 'documentation': 2, 'Welcome!': 1, ......
print(word_count['Python'])  # 输出3

7.3.3 写入文件

代码思路:

  • 路径不存在,创建路径
  • 写文件
  • 读取同一文件
  • 验证写入到文件的内容是否正确
import osdef write_to_file(file_path, file_name):if not os.path.exists(file_path):os.mkdir(file_path)whole_path_filename = os.path.join(file_path, file_name)to_write_content = ''' 什么是 Java?Java 是一项用于开发应用程序的技术,可以让 Web 变得更有意思和更实用。 Java 与 javascript 并不相同,后者是一种用于创建 Web 页的简单技术,只能在浏览器中运行。'''with open(whole_path_filename, mode="w", encoding='utf-8') as f:  # 以utf-8编码方式写入文件f.write(to_write_content)with open(whole_path_filename, encoding='utf-8') as f:content = f.read()print(content)if __name__ == '__main__':write_to_file(os.path.dirname(os.path.abspath(__file__)), "java.txt")  # 写入到当前py文件所在目录的java.txt中

7.3.4 文件的打开模式

open函数第一个参数是一个文件名称,可以使绝对路径也可以是相对当前py文件的相对路径。第二个参数是打开文件的模式,r表示以只读方式打开文件,w表示以覆盖写的方式打开文件,每次写操作都会覆盖之前的内容,x表示文件不存在的时候,先创建再写入。更多的模式可以通过通过help(open)可以查看帮助文档,很多模式可以组合使用。

========= ===============================================================Character Meaning--------- ---------------------------------------------------------------'r'       open for reading (default)'w'       open for writing, truncating the file first'x'       create a new file and open it for writing'a'       open for writing, appending to the end of the file if it exists'b'       binary mode't'       text mode (default)'+'       open a disk file for updating (reading and writing)'U'       universal newline mode (deprecated)========= ===============================================================

7.3.5 with妙用

open() 函数对应 close() 函数,用了with,就不需要手动调用close()函数了,Python会自动帮我们close文件。

7.4 序列化与反序列化

写程序我们经常是处理字典、列表、集合以及各种对象,这些对象都是在内存中的。如果我们想将处理完成后的对象保存到一个文件中或者是传输到网络中?该怎么办呢?这就要用到序列化。

我们知道,在文件中或者网络中,数据都是一个个字节序列,所以必须把对象转成字节序列,接着就可以写到文件或者传输到网络中了,将对象转成字节序列的过程就是序列化。反之,从文件读取字节序列或者从网络接收字节序列,将其转成对象的过程就是反序列化。

进行序列化的主要目的是:

  1. 持久化保存数据;
  2. 跨平台跨系统的数据交互;

7.4.1 pickle模块

pickle模块是python专用的持久化模块,可以持久化包括自定义类在内的各种数据;只能在python程序之间进行数据交换

看下pickle的官方文档,在Pycharm中,按两下shift,输入pickle则可跳转到源码文件。源码文件的开头有这样一段说明:

"""Create portable serialized representations of Python objects.See module copyreg for a mechanism for registering custom picklers.
See module pickletools source for extensive comments.Classes:PicklerUnpicklerFunctions:dump(object, file)dumps(object) -> stringload(file) -> objectloads(string) -> object

可见pickle模块提供了四个主要的函数:

  • dump——对象序列化到文件对象,就是存入文件;
  • dumps——将对象序列化成string;
  • load——对象反序列化,从文件读取数据;
  • loads——从bytes对象反序列化;

怎么记忆到底哪个函数时序列化,哪个函数是反序列化呢?一个办法是,站在内存的角度想,从内存出去就是序列化,进入到内存中就是反序列化。下面看一个使用pickle进行序列化和反序列化的用法:

import pickleclass Person:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):return "Name is {}, age is {}".format(self.name, self.age)__repr__ = __str__if __name__ == '__main__':p = Person("Mike", 19)with open("person.txt", 'wb') as wf:  # 序列化,以wb模式打开文件pickle.dump(p, wf)with open("person.txt", 'rb') as wf:  # 反序列化,以rb模式打开文件p_obj = pickle.load(wf)print("反序列化回来", p_obj)

7.4.2 Json模块

最常用的Json序列化,Json是一种轻量级的数据交换格式,跨平台语言,只能对python的基本数据类型进行序列化和反序列化。但是基本能满足大部分应用场景了。

在Pycharm中,按两下shift,输入json则可跳转到源码文件。源码文件中有很多例子,告诉我们如何使用。

  • 序列化:Python字典对象转成json字符串,json.dumps
import json
params = {    'symbol': '123456',    'type': 'limit',    'price': 123.4,    'amount': 23}
params_str = json.dumps(params)
  • 反序列化:json字符串转成Python字典,json.loads
original_params = json.loads(params_str)
  • 将Python字典对象写入到文件中,json.dump
import json
params = {    'symbol': '123456',    'type': 'limit',    'price': 123.4,    'amount': 23}
with open('params.json', 'w') as fout:    params_str = json.dump(params, fout)
  • 从json文件中读取字符串,转成Python字典,json.load
with open('params.json', 'r') as fin:    original_params = json.load(fin)

7.5 典型文件读写

7.5.1 ini文件

pytest.ini是Pytest提供的配置文件,用来设定pytest在运行中的行为。我的自动化测试项目中的配置如下:

[pytest]
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True
addopts = -rsxX -v --alluredir ./allure-results
markers =slow: marks tests as slow (deselect with '-m "not slow"')
console_output_style = countlog_file_level = DEBUG
log_file = test_result.log
log_file_date_format = %Y-%m-%d %H:%M:%S
log_file_format = %(asctime)s [%(filename)s:%(lineno)d] %(levelname)s: %(message)slog_cli = 1
log_cli_level = DEBUG
log_cli_date_format=%Y-%m-%d %H:%M:%S
log_cli_format = %(asctime)s [%(filename)s:%(lineno)d] %(levelname)s: %(message)s
  • addopts用来给pytest命令自动添加命令行的选项和参数。–rsxX表示pytest报告所有测试用例被跳过、预计失败、预计失败但实际通过的原因。这几个字母表示的含义可以通过$ pytest --help查看reporting部分。· --alluredir是我安装的allure-pytest插件提供的参数。

  • testpaths用来告诉pytest在哪里寻找测试用例。

  • markers表示注册的标记,这个marker用来对测试函数进行标记,比如@pytest.mark.smoke。如果addopts中设置了–strict选项,则必须在这里注册的marker才能在测试函数中使用。

  • console_output_style 用来在测试执行过程中,console上显示执行进度的方式, count表示显示执行到第几个,percentage表示执行的百分比。

  • log开头的那些用来表示日志的配置。上面对日志文件和日志的console输出进行了配置。设置了日志配置,就可以在测试函数中通过下面的方法记录日志了:

    import loggging
    def test_the_unknown(self):logging.info("跳过不执行,因为被测逻辑还没有被实现")assert 0
    

使用pytest --help指令可以查看pytest.ini的更多的选项:

[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:markers (linelist):   markers for test functionsempty_parameter_set_mark (string):default marker for empty parametersetsnorecursedirs (args): directory patterns to avoid for recursiontestpaths (args):     directories to search for tests when no files or directoriesare given in the command line.usefixtures (args):   list of default fixtures to be used with this projectpython_files (args):  glob-style file patterns for Python test module discoverypython_classes (args):prefixes or glob names for Python test class discoverypython_functions (args):prefixes or glob names for Python test function and methoddiscoverydisable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):disable string escape non-ascii characters, might causeunwanted side effects(use at your own risk)console_output_style (string):console output: "classic", or with additional progressinformation ("progress" (percentage) | "count").xfail_strict (bool):  default for the strict parameter of xfail markers when notgiven explicitly (default: False)enable_assertion_pass_hook (bool):Enables the pytest_assertion_pass hook.Make sure to deleteany previously generated pyc cache files.junit_suite_name (string):Test suite name for JUnit reportjunit_logging (string):Write captured log messages to JUnit report: one ofno|log|system-out|system-err|out-err|alljunit_log_passing_tests (bool):Capture log information for passing tests to JUnit report:junit_duration_report (string):Duration time to report: one of total|calljunit_family (string):Emit XML for schema: one of legacy|xunit1|xunit2doctest_optionflags (args):option flags for doctestsdoctest_encoding (string):encoding used for doctest filescache_dir (string):   cache directory path.filterwarnings (linelist):Each line specifies a pattern for warnings.filterwarnings.Processed after -W/--pythonwarnings.log_print (bool):     default value for --no-print-logslog_level (string):   default value for --log-levellog_format (string):  default value for --log-formatlog_date_format (string):default value for --log-date-formatlog_cli (bool):       enable log display during test run (also known as "livelogging").log_cli_level (string):default value for --log-cli-levellog_cli_format (string):default value for --log-cli-formatlog_cli_date_format (string):default value for --log-cli-date-formatlog_file (string):    default value for --log-filelog_file_level (string):default value for --log-file-levellog_file_format (string):default value for --log-file-formatlog_file_date_format (string):default value for --log-file-date-formatlog_auto_indent (string):default value for --log-auto-indentfaulthandler_timeout (string):Dump the traceback of all threads if a test takes more thanTIMEOUT seconds to finish. Not available on Windows.addopts (args):       extra command line optionsminversion (string):  minimally required pytest version

讲了这么多,应该知道如何配置pytest.ini来控制pytest的执行过程了。现在回归到本节的主题,如何对ini文件进行读写。Python内置了configparser模块来支持ini文件的读写。使用起来非常简单,先来看下读取ini的方法:

import configparser
config = configparser.ConfigParser()
config.read('../pytest.ini')
print(config)
section_list = config.sections()
print(section_list)
print(config['pytest']['addopts'])

再来看一下写ini的方法,很简单,就是给section赋值1个字典:

import os
import configparserconfig = configparser.RawConfigParser()  # 因为pytest.ini文件中有%,所有这里要用RawConfigParser() 类
file = 'pytest.ini'config['pytest'] = {'disable_test_id_escaping_and_forfeit_all_rights_to_community_support': True,'addopts': '-rsxX -l --tb=short --strict -v --alluredir ./allure-results','markers': "\nslow: marks tests as slow (deselect with '-m \"not slow\"')",'console_output_style': 'count','log_file_level': 'DEBUG','log_file': 'test_result.log','log_file_date_format': '%Y-%m-%d %H:%M:%S','log_file_format': '%(asctime)s [%(filename)s:%(lineno)d] %(levelname)s: %(message)s','log_cli': 1,'log_cli_level': 'DEBUG','log_cli_date_format': "%Y-%m-%d %H:%M:%S",'log_cli_format': '%(asctime)s [%(filename)s:%(lineno)d] %(levelname)s: %(message)s'}with open(file, 'a') as configfile:config.write(configfile)

7.5.2 yaml文件

YAML文件是软件领域常用的配置文件,YAML文件后缀为 .yml。使用空格缩进表示层级关系,空格多少没关系,只要同一层级左侧对齐即可。对大小写敏感,相比ini文件,我觉得更加友好的一点是,可以用#添加注释。

YAML文件中可以存放列表、字符串、数值、对象等数据类型。目前火热的容器集群管理系统Kubernetes中,各种API的配置文件都是使用YAML格式,下面以Kubernetes中Pod对象的YAML的为例,介绍一下YAML文件的格式。

apiVersion: v1  #必选,版本号,例如v1
kind: Pod  # 必选,表明这个yaml是个Pod对象
metadata:name: nginx  # 声明这个pod的名字是nginx
spec: #必选,Pod中容器的详细定义containers:  #必选,Pod中容器列表- name: nginx  #必选,容器1的名称, -开头表示列表元素image: nginx #必选,容器的镜像名称- name: shell  #必选,容器2的名称image: busyboxstdin: truetty: true

这个 YAML 文件定义了两个容器:一个是 nginx 容器,一个是开启了 tty 和 stdin 的 shell 容器。

Python中处理YAML文件需要安装PyYaml包。读取上面的YAML文件,方法很简单,通过yaml.load()将YAML文件内容转成一个字典。

import yamlwith open("pod.yml") as yml:pod = yaml.load(yml)  # pod是一个字典print(pod)print(type(pod))  # <class 'dict'>

上面的YAML文件转成字典是这样的:

{'apiVersion': 'v1','kind': 'Pod','metadata': {'name': 'nginx'},'spec': {'containers': [{'name': 'nginx','image': 'nginx'},{'name': 'shell','image': 'busybox','stdin': True,'tty': True}]}
}

接下来处理这个字典就很方便了。在自动化测试中,测试数据用YAML格式文件来存储既方便阅读,又方便使用。例如在接口自动化测试中,HTTP的请求对象和预期结果可以放到YAML文件中:

---
tests:
- case: 验证响应中start和count与请求中的参数一致  # 这是第一条casehttp:  # 这是请求对象,包括请求方法method、请求头headers、请求参数paramsmethod: GETpath: /v2/movie/in_theatersheaders:User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36params:apikey: 0df993c66c0c636e29ecbb5344252a4astart: 0count: 10expected:  # 这是预期结果,response表示接口的响应response:title: 正在上映的电影-上海count: 10start: 0
- case: 验证响应中title"正在上映的电影-北京"  # 这是第二条casehttp:method: GETpath: /v2/movie/in_theatersheaders:User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36params:apikey: 0df993c66c0c636e29ecbb5344252a4astart: 1count: 5expected:  response:title: 正在上映的电影-北京count: 5start: 1

测试开发之Python核心笔记(7):输入与输出相关推荐

  1. 测试开发之Python核心笔记(15):迭代器与生成器

    15.1 可迭代对象Iterable 还记得for循环吗?for循环可以循环迭代处理字符串以及列表.元组.字典.集合这些容器类型,知道为什么这些数据类型可以被for迭代吗?因为这些对象都是可迭代对象. ...

  2. 测试开发之Python核心笔记(19): 深入理解类的属性

    属性作为类的重要组成部分,除了平时常用的读取和设置操作之外,还有很多隐藏的.高级的操作.比如属性的查找顺序.属性的类型检查.限制属性的动态添加等等.这一小节,就让我们深入理解属性的各种高级操作. 19 ...

  3. Python学习笔记:输入和输出

    本文来自:入门指南 开胃菜参考:开胃菜 使用Python解释器:使用Python解释器 本文对Python的简介:Python简介 Python流程介绍:深入Python流程 Python数据结构:P ...

  4. 跟着王进老师学开发之Python篇第一季:基础入门篇-王进-专题视频课程

    跟着王进老师学开发之Python篇第一季:基础入门篇-2859人已学习 课程介绍         本季课程首先对Python简要介绍,然后演示如何搭建Python的开发环境,以及如何在IDE中调试Py ...

  5. 视频教程-跟着王进老师学开发之Python篇第一季:基础入门篇-Python

    跟着王进老师学开发之Python篇第一季:基础入门篇 教学风格独特,以学员视角出发设计课程,难易适度,重点突出,架构清晰,将实战经验融合到教学中.讲授技术同时传递方法.得到广大学员的高度认可. 王进 ...

  6. python输入数字翻译成星期几-Python练习笔记——计算输入日期为改年的第几天、星期几...

    # 输入年月日,如:1995年12月10日,计算是该年的第几天? # 同时计算出当天是星期几? print("请依据提示依次输入您想查询的年 月 日") # 第一段代码块(年月日输 ...

  7. Swift网络开发之NSURLSession学习笔记

    为什么80%的码农都做不了架构师?>>>    Swift网络开发之NSURLSession学习笔记 先上效果图:        功能: -单个任务下载 -暂停下载任务 -取消下载任 ...

  8. 电影天堂APP项目开发之Python爬虫篇,共18课时/5时33分

    电影天堂APP项目开发之Python爬虫篇,共18课时/5时33分,是电影天堂APP项目开发课程的第一篇章,讲解使用requests和bs4库,爬取和解析电影天堂网站数据,并讲数据保存到SQLite数 ...

  9. python输入,Python中的基本输入和输出

    从<安装Python和写出第一个Python程序>开始,我们就在屏幕上面开始输出了"Hello World",这个就使用到了print()函数向屏幕输出一些字符,这就是 ...

最新文章

  1. 在单块磁盘上安装2000和XP操作系统
  2. delete语句与reference约束冲突怎么解决_mysql update语句和原数据一样会更新么
  3. 多目标决策---基本概念
  4. 学计算机不会重装系统正常吗,系统重装不了的原因是什么 重装不了系统的解决方法【图文】...
  5. Linux tar命令
  6. dpkg制作deb包详解
  7. k8s篇-POD资源管理
  8. java web简单线上游戏_手把手教你用Java实现一个简易联网坦克对战小游戏 !
  9. 一年半的桌面运维经验小结,欢迎有类似经历的伙伴评论交流
  10. 《工程测量学》考试复习总结
  11. SpringCloud入门总结 + 使用SpringCloud搭建微服务项目
  12. iNode客户端“未收到服务器回应,即将强行下线,请检查终端能否正常访问网络或者与管理员联系”问题与解决方式
  13. 美学心得(第二百二十四集)罗国正
  14. THREADED_EXECUTION
  15. VC加载jpeg, png图片的方法
  16. 一文了解加密游戏illuvium新玩法:探索神兽世界
  17. OpenSSL命令之算法类大全
  18. 系统学习------IPtables包过滤防火墙
  19. html css 边框不显示,css怎么设置不显示下边框?
  20. Python 终极指南:进阶之路

热门文章

  1. java netty wss_netty 配置 wss访问
  2. iOS - 蓝牙开门智能门锁
  3. Discuz!NT 代码阅读笔记(8)--DNT的几个分页存储过程解析
  4. linux命令的使用:配置静态ip,查看网关,dns服务器ip,关闭防火墙,selinux
  5. python 股票市场分析实战
  6. windows黑客编程系列(十一):按键记录
  7. 记事本打开文件乱码的问题
  8. 分享几个学习练习盲打的网站
  9. 迫在眉睫的企业内控与跃跃欲试的IT
  10. 为什么没有参数的函数(与实际函数定义相比)会编译?