抽象的来说,我们的电脑就像是一个黑箱,同样Python程序也是一个黑箱,通过输入流将数据送达,通过输出流将处理后的数据送出。
输入输出基础
最简单直接的输入来自键盘操作,比如下面这个例子。
name = input('your name:')
gender = input('you are a boy?(y/n)')
###### 输入 ######
your name:Jack
you are a boy?
welcome_str = 'Welcome to the matrix {prefix} {name}.'
welcome_dic = {
'prefix': 'Mr.' if gender == 'y' else 'Mrs',
'name': name
}
print('authorizing...')
print(welcome_str.format(**welcome_dic))
########## 输出 ##########
authorizing...
Welcome to the matrix Mr. Jack.
input() 函数暂停程序运行,同时等待键盘输入;直到回车被按下,函数的参数即为提示语,输入的类型永远是字符串型(str),print() 函数则接受字符串、数字、字典、列表甚至一些自定义类的输出。
请注意,上边说输入的类型永远是字符串型,是啥意思,举个例子。
a = input()
1
b = input()
2
print('a + b = {}'.format(a + b))
########## 输出 ##############
a + b = 12
print('type of a is {}, type of b is {}'.format(type(a), type(b)))
########## 输出 ##############
type of a is , type of b is
print('a + b = {}'.format(int(a) + int(b)))
########## 输出 ##############
a + b = 3
前边定义的a和b,你输入的是1,但如果你直接打印的话就能看出来a的输出是“1”,是个字符串,对a,b进行相加实际上是对字符串进行的拼接。想进行数字相加减,就必须进行类型转换。
Python 对 int 类型没有最大限制(相比之下, C++ 的 int 最大为 2147483647,超过这个数字会产生溢出),但是对 float 类型依然有精度限制。这些特点,除了在一些算法竞赛中要注意,在生产环境中也要时刻提防,避免因为对边界条件判断不清而造成 bug 甚至 0day(危重安全漏洞),虽然输入输出和类型处理事情简单,但我们一定要慎之又慎。毕竟相当比例的安全漏洞,都来自随意的 I/O 处理。
文件输入输出
命令行的输入输出,只是 Python 交互的最基本方式,适用一些简单小程序的交互。而生产级别的 Python 代码,大部分 I/O 则来自于文件、网络、其他进程的消息等等。
接下来,我们来详细分析一个文本文件读写。假设我们有一个文本文件 in.txt,内容如下:
#这是个文本
I have a dream that my four little children will one day live in a nation where they will not be judged by the color of their skin but by the content of their character. I have a dream today.
I have a dream that one day down in Alabama, with its vicious racists, . . . one day right there in Alabama little black boys and black girls will be able to join hands with little white boys and white girls as sisters and brothers. I have a dream today.
I have a dream that one day every valley shall be exalted, every hill and mountain shall be made low, the rough places will be made plain, and the crooked places will be made straight, and the glory of the Lord shall be revealed, and all flesh shall see it together.
This is our hope. . . With this faith we will be able to hew out of the mountain of despair a stone of hope. With this faith we will be able to transform the jangling discords of our nation into a beautiful symphony of brotherhood. With this faith we will be able to work together, to pray together, to struggle together, to go to jail together, to stand up for freedom together, knowing that we will be free one day. . . .
And when this happens, and when we allow freedom ring, when we let it ring from every village and every hamlet, from every state and every city, we will be able to speed up that day when all of God's children, black men and white men, Jews and Gentiles, Protestants and Catholics, will be able to join hands and sing in the words of the old Negro spiritual: "Free at last! Free at last! Thank God Almighty, we are free at last!"
让我们来做一个简单的 NLP(自然语言处理)任务。
首先,我们要清楚 NLP 任务的基本步骤,也就是下面的四步:
1、读取文件;
2、去除所有标点符号和换行符,并把所有大写变成小写;
3、合并相同的词,统计每个词出现的频率,并按照词频从大到小排序;
4、将结果按行输出到文件 out.txt。
import re
def parse(text):
# 使用正则表达式去除标点符号和换行符
text = re.sub(r'[^\w ]', ' ', text)
# 转为小写
text = text.lower()
# 生成所有单词的列表
word_list = text.split(' ')
# 去除空白单词
word_list = filter(None, word_list)
# 生成单词和词频的字典
word_cnt = {}
for word in word_list:
if word not in word_cnt:
word_cnt[word] = 0
word_cnt[word] += 1
# 按照词频排序
sorted_word_cnt = sorted(word_cnt.items(), key=lambda kv: kv[1], reverse=True)
return sorted_word_cnt
with open('in.txt', 'r') as fin:
text = fin.read()
word_and_freq = parse(text)
with open('out.txt', 'w') as fout:
for word, freq in word_and_freq:
fout.write('{} {}\n'.format(word, freq))
########## 输出(省略较长的中间结果) ##########
and 15
be 13
will 11
to 11
the 10
of 10
a 8
we 8
day 6
...
old 1
negro 1
spiritual 1
thank 1
god 1
almighty 1
are 1
我们先要用 open() 函数拿到文件的指针。其中,第一个参数指定文件位置(相对位置或者绝对位置);第二个参数,如果是 'r'表示读取,如果是'w' 则表示写入,当然也可以用 'rw' ,表示读写都要。a 则是一个不太常用(但也很有用)的参数,表示追加(append),这样打开的文件,如果需要写入,会从原始文件的最末尾开始写入。
在拿到指针后,我们可以通过 read() 函数,来读取文件的全部内容。代码 text = fin.read() ,即表示把文件所有内容读取到内存中,并赋值给变量 text。一般情况下,这么做非常方便,直接调用函数处理读入内存的数据,但是如果文件过大,一下子全读到内存的话,容易造成内存崩溃。
这时,我们可以给 read 指定参数 size ,用来表示读取的最大长度。还可以通过 readline() 函数,每次读取一行,这种做法常用于数据挖掘中的数据清洗,在写一些小的程序时非常轻便。如果每行之间没有关联,这种做法也可以降低内存的压力。而 write() 函数,就是可以把参数中的字符串输出到文件中。
然后是 with 语句,open() 函数对应于 close() 函数,也就是说,如果你打开了文件,在完成读取任务后,就应该立刻关掉它。而如果你使用了 with 语句,就不需要显式调用 close()。在 with 的语境下任务执行完毕后,close() 函数会被自动调用,代码也简洁很多。
json序列化和反序列化
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它的设计意图是把所有事情都用设计的字符串来表示,这样既方便在互联网上传递信息,也方便人进行阅读。
举个例子,你要向交易所购买一定数额的股票。那么,你需要提交股票代码、方向(买入 / 卖出)、订单类型(市价 / 限价)、价格(如果是限价单)、数量等一系列参数,而这些数据里,有字符串,有整数,有浮点数,甚至还有布尔型变量,全部混在一起并不方便交易所解包。
JSON ,正能解决这个情况。你可以把它简单地理解为两种黑箱:第一种,输入这些杂七杂八的信息,比如 Python 字典,输出一个字符串;第二种,输入这个字符串,可以输出包含原始信息的 Python 字典。
import json
data = {
'name' : 'ACME',
'shares' : 100,
'price' : 542.23
}
json_str = json.dumps(data)
print('json序列化')
print('type of json_str = {}, json_str = {}'.format(type(json_str), json_str))
json_str= json.loads(json_str)
print('json反序列化')
print('type of json_str= {}, json_str= {}'.format(type(str_json), str_json))
######输出#######
json序列化
type of json_str = , json_str = {"name": "ACME", "shares": 100, "price": 542.23}
json反序列化
type of str_json = , str_json = {'name': 'ACME', 'shares': 100, 'price': 542.23}json.dumps() ,接受 Python 的基本数据类型,然后将其序列化为 string;
json.loads(),接受一个合法字符串,然后将其反序列化为 Python 的基本数据类型。
如果你想从文件中读取json字符串,那就和上边一样用open、read(),等函数把文件读取到内存进行操作,写入文件也是同样的道理。
#读取json文件
with open('data.json', 'r') as f:
data = json.load(f)
#将数据写成json文件
with open('data.json', 'w') as f:
json.dump(data, f)json.load()读取json格式文件
json.dump()将数据写成json文件
pickle 模块
python的pickle模块也是实现基本的数据序列和反序列化。
通过pickle模块的序列化操作我们能够将程序中运行的对象信息保存到文件中去,永久存储。
通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象。
其用法跟json的用法很相似。
import pickle
# 使用pickle模块将数据对象保存到文件
data1 = {'a': [1, 2.0, 3, 4+6j],
'b': ('string', u'Unicode string'),
'c': None}
selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)
output = open('data.pkl', 'wb')
# Pickle dictionary using protocol 0.
pickle.dump(data1, output)
# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)
output.close()
import pprint, pickle
#使用pickle模块从文件中重构python对象
pkl_file = open('data.pkl', 'rb')
data1 = pickle.load(pkl_file)
pprint.pprint(data1)
data2 = pickle.load(pkl_file)
pprint.pprint(data2)
pkl_file.close()