Python核心技术与实战学习笔记(四):python黑箱:输入与输出

本文介绍了Python的输入输出基础,包括input()函数和强制类型转换,强调了错误处理的重要性。接着讲解了文件输入输出,以词频统计为例展示了读写文件的操作,并推荐使用with语句处理文件。最后提到了JSON序列化,解释了如何将数据转换为JSON字符串以及反序列化,并指出在实际应用中处理文件的JSON编码和解码。文章提醒开发者注意边界条件和异常处理,以确保程序稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4.1 输入输出基础

最简单的输入输出:

  • age = input(“how old are you?”) :特别需要注意input()函数的用法的是,输入的变量最终都存储为字符串类型
  • print()
a = input()
1
b = input()
2

print('a + b = {}'.format(a + b))
########## 输出 ##############
a + b = 12        # 注意是字符串12而不是整数3
print('type of a is {}, type of b is {}'.format(type(a), type(b)))
########## 输出 ##############
type of a is <class 'str'>, type of b is <class 'str'>
print('a + b = {}'.format(int(a) + int(b)))
########## 输出 ##############
a + b = 3

强制转换的注意事项

上面的代码中用到了强制类型转换,在Python中:

  • 把 str 强制转换为 int 要用 int(),转为浮点数要用float()
  • 在生产环境使用强制类型转换时,要记得使用错误和异常处理(try…except)

Python中的int类型没有最大限制(相比之下,C++的int最大为2147483647,超过这个数字就会产生溢出),但对float类型有精度限制。这些特点除了在一些算法竞赛中要注意,在生产环境中也要时刻堤防,避免因边界问题不清而引起bug甚至0day(危重安全漏洞)

有相当比例的安全漏洞,都来自于随意的I/O操作

4.2 文件输入输出

生产级别的Python代码,大部分I/O则来自文件,网络,其他进程的消息

以下是一个简单的NLP任务:读取文件中的文本,统计词频将统计结果存储在新建文件中
在这里插入图片描述

NLP小任务——词频统计:

import re
def parse(text, word_count_dic):
    
    # 大写转小写
    text = text.lower()
    
    # 构建这一行字符串的单词列表
    word_list = re.findall(r'\w+',text)
    
    # 统计出现的各个单词以及的次数,存于字典结构中
    for word in word_list:
        word_count_dic[word] = word_count_dic.get(word, 0) + 1  # 这里还可以使用defaultdict字典
 
    return word_count_dic

fin_path = 'G:\Python_Projects\I have a dream.txt'
fout_path = 'G:\Python_Projects\I have a dream parse.txt'

with open(fin_path, 'r') as fin:
    word_count_dic = {}
    
    # 逐行读取再进行处理而不是直接fin.read(),避免文件过大一次读入会爆内存
    for line in fin:
        word_count_dic = parse(line, word_count_dic)

with open(fout_path, 'w') as fout:
    # 将单词按出现的词频排序,sorted()函数返回的 word_count_dic为二元组列表(list of tuples)
    word_count_dic = sorted(word_count_dic.items(), key=lambda x:x[1], reverse=True)
    
    for word, freq in word_count_dic:
        fout.writelines(f"{word}:{freq}\n")

上面的代码:

 word_count_dic[word] = word_count_dic.get(word, 0) + 1

完成了对词频的更新,在这里介绍另一种方法:可使用collections里的defaultdict字典,接受工厂函数作为参数,如dict =defaultdict( factory_function),作用是当key不存在时,返回的是工厂函数的默认值,int对应0,list对应[],str对应的是空字符串,set对应set( )

以下是利用defaultdict完成对文本词频的统计:

from collections import defaultdict
import re

f = open("ini.txt", mode="r", encoding="utf-8")
dic = defaultdict(int)   # 若key不存在,添加该键且对应value为int的默认值0

for line in f:
    for word in filter(lambda x: x, re.split(r"\s", line)):
        dic[word] += 1
print(dic)
  • open(path, “r”/“w”/“rw”/“a”)函数拿到文件的指针("w"模式注意覆盖问题)
  • f.read(size)指定读取的字串长度大小
  • 尽量用with语句打开文件,函数会自动到之后关闭文件,就不需要自己再写f.close()

需要注意的是,所有I/O操作都需要错误和异常处理,因为I/O操作可能有各种各样的情况出现,否则可能会导致程序崩溃

4.3 JSON序列化与实战

之前学习过用“泡菜”pickle存储文件数据,这里的JSON也有类似的功能和实现方法

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它的设计意图是把所有事情都用设计的字符串表示,这样便于信息的传递和阅读(相比一些binary协议)

下面以一个应用场景来运用JSON:
在这里插入图片描述
JSON就能解决这种场景,我们可以把JSON理解为这样的两种黑箱:

  • 第一种: \quad 输入:一些杂乱的信息(如字典); \quad 输出:一个字符串
  • 第二种: \quad 输入:一个字符串; \quad 输出:原始信息(字典)

具体代码如下:

import json

params = {
    'symbol': '123456',
    'type': 'limit',
    'price': 123.4,
    'amount': 23
}

params_str = json.dumps(params)

print('after json serialization')
print('type of params_str = {}, params_str = {}'.format(type(params_str), params))

original_params = json.loads(params_str)

print('after json deserialization')
print('type of original_params = {}, original_params = {}'.format(type(original_params), original_params))

########## 输出 ##########

after json serialization
type of params_str = <class 'str'>, params_str = {'symbol': '123456', 'type': 'limit', 'price': 123.4, 'amount': 23}
after json deserialization
type of original_params = <class 'dict'>, original_params = {'symbol': '123456', 'type': 'limit', 'price': 123.4, 'amount': 23}

其中:

  • json.dumps()这个函数接收Python的基本数据类型,并将其序列化为字符串
  • json.loads()这个函数接收一个合法的字符串,并将其反序列化为Python的基本数据类型

还是需要注意的是,记得加上错误和异常处理。否则,哪怕只是给json.loads()传递了一个非法字符串却没有catch到,程序就会奔溃。

若要输出字符串到文件,或者从文件中读取json字符串,也即涉及文件操作的JSON解码/编码的情况,这时要用json.dump(params, file)json.load(file)

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)

with open('params.json', 'r') as fin:
    original_params = json.load(fin)

print('after json deserialization')
print('type of original_params = {}, original_params = {}'.format(type(original_params), original_params))

########## 输出 ##########

after json deserialization
type of original_params = <class 'dict'>, original_params = {'symbol': '123456', 'type': 'limit', 'price': 123.4, 'amount': 23}

当开发一个第三方应用程序时,可以使用JSON将用户的个人配置保存输出到文件,方便下次程序启动时自动读取。这也是现在普遍使用的成熟做法。

在这里插入图片描述
思考题:
在这里插入图片描述
省略了一些异常处理:

server.py
# 我们假设 server 电脑上的所有的文件都在 BASR_DIR 中,为了简化不考虑文件夹结构,网盘的路径在 NET_DIR

import os
from shutil import copyfile
import time

BASE_DIR = 'server/'
NET_DIR = 'net/'

def main():
    filenames = os.listdir(BASE_DIR)
    for i, filename in enumerate(filenames):
        print('copying {} into net drive... {}/{}'.format(filename, i + 1, len(filenames)))
        copyfile(BASE_DIR + filename, NET_DIR + filename)
        print('copied {} into net drive, waiting client complete... {}/{}'.format(filename, i + 1, len(filenames)))

        while os.path.exists(NET_DIR + filename):
            time.sleep(3)

    print('transferred {} into client. {}/{}'.format(filename, i + 1, len(filenames)))

if __name__ == "__main__":
	main()
client.py
# 我们假设 client 电脑上要输出的文件夹在 BASR_DIR ,网盘的路径在 NET_DIR

import os
from shutil import copyfile
import time

BASE_DIR = 'client/'
NET_DIR = 'net/'

def main():
    while True:
        filenames = os.listdir(NET_DIR)
        for filename in filenames:
            print('downloading {} into local disk...'.format(filename))
            copyfile(NET_DIR + filename, BASE_DIR + filename)
            os.remove(NET_DIR + filename) # 我们需要删除这个文件,网盘会提我们同步这个操作,从而 server 知晓已完成
            print('downloaded {} into local disk.'.format(filename))
        time.sleep(3)

if __name__ == "__main__":
	main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值