Python模块系列之--模块与包【18】

真正的无知不是知识的贫乏, 而是拒绝获取知识!
——波普尔 (哲学家 思想家)

[toc]

##目标

  • 掌握常用的文件目录操作
  • 学习with关键字
  • 练习题

第一部分 os模块

os模块是Python标准库中的一个用于访问操作系统相关功能的模块,os模块提供了一种可移植的使用操作系统功能的方法。

1. os模块的主要功能:

  1. 系统相关
  2. 目录及文件操作
  3. 执行命令和管理进程

2. 文件及目录相关

方法 说明
os.mkdir 创建目录
os.rmdir 删除目录
os.rename 重命名
os.remove 删除文件
os.getcwd 获取当前工作路径
os.walk 遍历目录
os.path.join 连接目录与文件名
os.path.split 分割文件名与目录
os.path.abspath 获取绝对路径
os.path.dirname 获取路径
os.path.basename 获取文件名或文件夹名
os.path.splitext 分离文件名与扩展名
os.path.isfile 判断给出的路径是否是一个文件
os.path.isdir 判断给出的路径是否是一个目录

背诵这种真的没啥意义,不如来个实例记得快些。网上找了个实例,来源python 文件操作练习题, 稍加改动,还有bug,但包含了一些常用的方法。

# pylint: disable=no-member
import os

while True:
mulu = input('请输入目录:')
if os.path.exists(mulu): # 判断是否存在此目录
os.chdir(mulu) # 改变当前脚本工作目录;相当于shell下cd
ret = os.listdir(os.getcwd()) # 打印出此目录的所有文件
print(ret)
lst1 = []
lst2 = []
for i in ret:
if os.path.isfile(i): # 判断是否是文件
lst1.append(i)
else:
lst2.append(i)
print('文件:%s' % lst1)
print('文件夹:%s' % lst2)
ret1 = input('请选择操作:全部文件添加前缀(a) 全部删除前缀(s) 添加文件(d) 删除文件(f) 单个文件重命名(g):')
if ret1.upper() == 'A':
a = input('请输入所要添加的前缀:')
for i in ret: # 便利所有文件,
os.rename(i, a + i) # 使用字符串拼接,添加前缀
print('添加成功')
elif ret1.upper() == 'S':
a = input('请输入所要删除的前缀:')
for i in ret:
os.rename(i, i.replace(a, '', 1))
print('删除前缀成功')
elif ret1.upper() == 'D':
file_name = input('请输入所要添加文件名称:')
with open(file_name, mode='w') as f:
pass
print('添加文件成功')
elif ret1.upper() == 'F':
del_name = input('请输入所要删除的文件名:')
os.remove(del_name)
print('删除文件成功')
elif ret1.upper() == 'G':
name = input('请输入原始文件名[old name]:')
if name.strip() == '':
name = input('不可为空,请输入原始文件名[old name]:')

newName = input('请输入新的文件名[new name]:')
if newName.strip() == '':
newName = input('不可为空,请输入新的文件名[old name]:')

os.rename(name, newName)
print('修改成功')
os.chdir('..') # 留在当前目录 以防输入两次文件夹名称报错
else:
print('输入有误,请重新输入')

第二部分 with关键字

第一部分中的with究竟是什么意思?为何要用with呢?

pyhton2.5中加入with, 常用来替换try ... except ... finally ....

我们采用事务链接时,会着这样判断

db.begin()
try:
# do some actions
except:
db.rollback()
raise
else:
db.commit()

如果将发起事务请求的操作变成可以支持with关键字的,那么用像这样的代码就可以了:

with transaction(db):
# do some actions

第一部分的with就是保证读取文件内容时,不论出现什么意外,都保证最终关闭。

with open('file.txt') as f:
content = f.read()

with 的一般执行过程

一段基本的with表达式,其结构是这样的:

with EXPR as VAR:
BLOCK

其中:EXPR可以是任意表达式;as VAR是可选的。其一般的执行过程是这样的:

  1. 计算EXPR,并获取一个上下文管理器。
  2. 上下文管理器的exit()方法被保存起来用于之后的调用。
  3. 调用上下文管理器的enter()方法。
  4. 如果with表达式包含as VAR,那么EXPR的返回值被赋值给VAR。
  5. 执行BLOCK中的表达式。
  6. 调用上下文管理器的exit()方法。如果BLOCK的执行过程中发生了一个异常导致程序退出,那么异常的type、value和traceback(即sys.exc_info()的返回值)将作为参数传递给exit()方法。否则,将传递三个None。

实现类似的with过程

class transaction(object):
def __init__(self, db):
self.db = db

def __enter__(self):
self.db.begin()

def __exit__(self, type, value, traceback):
if type is None:
db.commit()
else:
db.rollback()

基于装饰器的方法或更相信教程可参考Python 中的关键字with详解

第三部分 习题

狗东二面笔试题

  1. 生成一个大文件ips.txt,要求1200行,每行随机为172.25.254.0/24段的ip;
  2. 读取ips.txt文件统计这个文件中ip出现频率排前10的ip;

分析

  1. 172.25.254.0/24,前24位为网络号,后八位为主机号,[0-255);
  2. 1200行,写入ips.txt文件
  3. 统计次数,抽出前十条
import random


def create_ip_file(filename):
# 172.25.254.[0,255)
ip = ['172.25.254.' + str(i) for i in range(0, 255)]
with open(filename, 'a+') as f:
# print(random.sample(ip,1))
# 随机从数组中取第一个
[f.write(random.sample(ip, 1)[0] + '\n') for i in range(1200)]


create_ip_file('ips.txt')


def sorted_by_ip(filename, count=10):
ips_dict = dict()
with open(filename) as f:
for ip in f:
if ip in ips_dict:
ips_dict[ip] += 1
else:
ips_dict[ip] = 1
print(ips_dict.items())
sorted_ip = sorted(
ips_dict.items(), key=lambda x: x[1], reverse=True)[:count]
return sorted_ip


print(sorted_by_ip('ips.txt'))

结果

[('172.25.254.49\n', 14), ('172.25.254.80\n', 12), ('172.25.254.172\n', 11), ('172.25.254.65\n', 11), ('172.25.254.45\n', 10), ('172.25.254.30\n', 10), ('172.25.254.8\n', 10), ('172.25.254.196\n', 9), ('172.25.254.53\n', 9), ('172.25.254.121\n', 9)]

参考
Python 中的关键字with详解
python文件操作练习题