《Python核心编程》第九章练习解析

博客开通很长时间了也没发个正式的文章,最近也是各种蛋疼,终于零零散散的把第九章的解析写完了,以后发博文的数量可能不多,但会尽量多写一些干货。

一至八章练习解析:传送门

第一题:

文件过滤. 显示一个文件的所有行, 忽略以井号( # )开头的行. 这个字符被用做Python , Perl, Tcl, 等大多脚本文件的注释符号. 附加题: 处理不是第一个字符开头的注释. 

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def count(filepath):
    f = open(filepath)
    for line in f:
        if line[0]!='#':
            print line

if __name__=='__main__':
    filepath = raw_input(r'Please input file path:')
    count(filepath)

第二题:

文件访问. 提示输入数字 N 和文件 F, 然后显示文件 F 的前 N 行.

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def output(filepath,linenum):
    f = open(filepath)
    for line in f:
        linenum -= 1
        print line,
        if linenum <= 0:
            break

if __name__=='__main__':
    filepath = raw_input(r'Please input file path:')
    linenum = input('Please input lines:')
    output(filepath,linenum)

第三题:

文件信息. 提示输入一个文件名, 然后显示这个文本文件的总行数。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def count(filepath):
    f = open(filepath)
    alllines = f.readlines()
    count_line = len(alllines)
    return count_line

if __name__=='__main__':
    filepath = raw_input(r'Please input file path:')
    lines = count(filepath)
    print 'File has %d lines' % lines

第四题:

文件访问. 写一个逐页显示文本文件的程序. 提示输入一个文件名, 每次显示文本文件25 行, 暂停并向用户提示"按任意键继续.", 按键后继续执行.

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def readfile(filepath):
    count = 25
    f = open(filepath)
    for line in f:
        if count > 0:
            print line
            count -= 1
        else:
            count = 25
            temp = raw_input('Please input anything to continue:')
            continue

if __name__=='__main__':
    filepath = raw_input(r'Please input file path:')
    readfile(filepath)

第五题:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def readfile(filepath):
    f = open(filepath)
    for line in f:
        if int(line)>=90:
            print 'A'
        elif int(line)>=80:
            print 'B'
        elif int(line)>=70:
            print 'C'
        elif int(line)>=60:
            print 'D'
        else:
            print 'F'

if __name__=='__main__':
    filepath = raw_input(r'Please input file path:')
    readfile(filepath)

第六题:

文件比较. 写一个比较两个文本文件的程序. 如果不同, 给出第一个不同处的行号和列号。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

def comparefile(filepath1,filepath2):
    f1 = open(filepath1)
    f2 = open(filepath2)
    count_line = 0
    for line1,line2 in zip(f1,f2):
        count_line += 1
        if line1 != line2:
            count_list = 0
            for i,j in zip(line1,line2):
                count_list += 1
                if i != j:
                    print 'The diffrent is %d line and %d list' % (count_line,count_list)
                    break
            if count_list != 0:
                break

if __name__=='__main__':
    filepath1 = raw_input(r'Please input first file path:')
    filepath2 = raw_input(r'Please input second file path:')
    comparefile(filepath1,filepath2)
    print 'Done!'

第七题:

解析文件。Win32用户,创建一个用来解析Windows.ini文件的程序。POSIX用户,创建一个解析/etc/serves文件的程序。其它平台的用户,写一个解析特定结构的系统配置文件的程序。

这里我就解析windows.ini文件吧,对linux还不是很熟。首先要了解一下ini文件的格式,ini文件主要包括这三个部分parameters、sections、comments,其中parameters是参数,形式为name=value;sections是节,由多个parameters组成,sections的名称有[]括起来;comments是注释,由;标识。解析的思路就是把parameters和sections的隶属关系准确的划分出来。

#-*- coding:utf-8 -*-

def readini(filepath):
    sections = {}
    with open(filepath) as f:
        for item in f:
            if item.startswith(';'):
                continue
            if item.startswith('['):
                parameters = {}
                name = item[1:item.rfind(']')]
                sections[name] = parameters
                continue
            if item.count('=') > 0 and parameters != None:
                index = item.find('=')
                key = item[0:index]
                value = item[index+1:].strip()
                parameters[key] = value
    return sections

if __name__ == '__main__':
    path = raw_input('Please input filepath:')
    result = readini(path)
    for key in result:
        if len(result[key])!=0:
            print '%s:' % key,
            for flag in result[key]:
                print '%s=%s ' % (flag,result[key][flag]),
            print 'n',
        else:
            print key

第八题:

模块研究。提取模块的属性资料,提示用户输入一个模块名,然后使用dir()和其他内建函数提取模块的属性,显示它们的名字、类型、值。

#-*- coding:utf-8 -*-

def check_model(name):
    name = raw_input('module name: ')
    obj = __import__(name)
    ls = dir(obj)
    for item in ls:
        print 'name: ', item
        print 'type: ', type(getattr(obj, item))
        print 'value: ', getattr(obj, item)
        print 
    
if __name__ == '__main__':
    name = raw_input('module name: ')
    check_model(name)

第九题:

Python文档字符串。进入Python标准库所在的目录,检查每个.py文件看是否有__doc__字符串,如果有,对其格式进行适当的整理归类。你
的程序执行完毕后,应该会生成一个漂亮的清单,里边列出哪些模块有文档字符串,以及文档字符串的内容,清单最后附上那些没有文档字符串模块的名字。

附加题:提取标准库中各模块内全部类和函数的文档。

os模块处理这类问题非常方便,此程序会在桌面生成一个doc.txt文件,文件中整洁的记录了每个文件__doc__字符串

#-*- coding:utf-8 -*-
import os  

def check_doc(path):
    f = open(r'C:UsersAdministratorDesktopdoc.txt','w')
    f.write('__doc__ in there files:nnn')
    temp  =[]
    for parent,localdir,filenames in os.walk(path):
        for file in filenames:
            print filenames
            if '__doc__' in dir(file):
                f.write(file+':'+file.__doc__+'nnn')
            else:
                temp.append(file)
    f.write('__doc__ not in there files:nnn')
    for i in temp:
        f.write(i+'nnn')
        
if __name__ == '__main__':
    check_doc(r'D:python27Lib')

第十题:

家庭理财,创建一个家庭理财程序。你的程序需要处理储蓄、支票、金融市场,定期存款等多种账户。为每种账户提供一个菜单操作界面,要有存款、取款、借、贷等操作。另外还要提供一个取消操作选项。用户退出这个程序时相应的数据应保存到文件中。(出去备份的目的,程序运行的过程中也要备份)

本程序用shelve模块处理数据储存,用copy模块创建备份,详细信息请看注释:

#-*- coding:utf-8 -*-

import os
import shelve
from shutil import copy

def new_user():
    '''用户新建程序,初始化数据'''
    name = raw_input('Please input your new name:')
    db = shelve.open(name+'.dat','c')
    db['M'] = 0
    db['D'] = 0
    db['W'] = 0
    db['B'] = 0
    db['L'] = 0
    db.close()
    print 'Successful!'

def account(order):
    '''数据处理函数,负责主要的数据操作'''
    name = raw_input('Please input your name:')
    name = name+'.dat'
    copy(name, name+'~')  #创建备份文件
    if name in os.listdir(os.getcwd()):
        db = shelve.open(name, 'c',True)
        money = input('Please input money:')
        if order == 'D':
            db['D'] = db['D']+money  #存款
        elif order == 'W':
            db['W'] = db['W']+money  #取款
        elif order == 'B':
            db['B'] = db['B']+money  #借
        elif order == 'L':
            db['L'] = db['L']+money  #贷
        db['M'] = db['D']-db['W']+db['B']-db['L']  #总金额
    else:
        print 'Account not exite!'
        choice = raw_input('Dou you want to create a new account? Yes or No:')
        if choice == 'Yes':
            new_user()
        else:
            pass

def help():
    print '''
M   :Money
N   :New user
D   :Deposit
W   :Withdraw money
B   :Borrow
L   :Loan
C   :Check account
Q   :Quit
H   :Help'''

def check_account():
    '''账户信息查看程序'''
    name = raw_input('Please input your name:')+'.dat'
    db = shelve.open(name, 'r')
    for item in db.items():
        print '%-10s:%10d' % (item[0],item[1])
    

def menu():
    '''菜单主程序'''
    print 'Welcome to Account System!'
    while True:
        order = raw_input('What do you want(H :help):')
        if order in 'MNCDWBLQH':
            if order == 'Q':  #退出
                break
            elif order == 'H':  #查看帮助信息
                help()
            elif order == 'N':  #新建用户
                new_user()
            elif order == 'C':  #查看用户信息
                check_account()
            else:
                account(order)
        else:
            print 'Invalid order,Please input again'
        print 'n'
                
if __name__ == '__main__':
    menu()

第十一题:

(a)编写一个URL书签管理程序。使用基于文本的菜单,用户可以添加、修改或者删除书签数据项,书签数据项中包含站点名称、URL和一行简单说明(可
选)。另外提供检索功能,可以根据检索关键字在站点名称和URL两部分查找可能的匹配。程序退出时把数据保存到一个磁盘文件中去,再次执行时加载保存的数
据。

(b)改进(a)的方案,把书签输出到一个合法且语法正确的HTML文件中,这样用户就可以使用浏览器查看自己的书签清单。另外提供创建“文件夹”功能,对相关的书签进行分组管理。

附加题:请阅读Python的re模块了解有关的正则表达式的资料,使用正则表达式对用户输入的URL进行验证。

#-*- coding:utf-8 -*-

import re 

def re_check(url):
    m = re.search(r"w{3}.w*.net|w{3}.w*.com|w{3}.w*.cn",url)  #匹配符合条件的URL
    if m:
        return True
    else:
        return False

def URL(order):
    '''功能函数,负责书签的曾、查、改、删'''
    if order == 'add':
        db = open('url.html','a')
        data = raw_input('Please input URL_name URL_value:').split()
        if re_check(data[1]):
            doc = raw_input('Please input simple txt:')
            db.write(r"<p><a href=http://"+data[1]+r">"+data[0]+r"</a>"+r"---------------->"+doc+r"</p>"+"n")  #以html标签的形式写入,可被浏览器识别
        else:
            print 'Error URL'
    elif order == 'del':
        db = open('url.html','r')
        data = db.readlines()
        db.close()
        name = raw_input('Please input the url name you want to del:')
        for line in data:
            if name in line:
                data.remove(line)
                break 
        db = open('url.html','w')
        db.writelines(data)
        db.close()
    elif order == 'cha':
        db = open('url.html','r')
        data = db.readlines()
        db.close()
        name = raw_input('Please input the url name you want to change:')
        length = len(data)
        for i in range(length):
            if name in data[i]:
                temp = raw_input('Please input URL_name URL_value:').split()
                if re_check(temp[1]):
                    doc = raw_input('Please input simple txt:')
                    data[i] = r"<p><a href=http://"+temp[1]+r">"+temp[0]+r"</a>"+r"---------------->"+doc+r"</p>"+"n"
                else:
                    print 'Error URL'
                break 
        db = open('url.html','w')
        db.writelines(data)
        db.close()
    elif order == 'che':
        db = open('url.html','r')
        data = db.readlines()
        db.close()
        for line in data:
            print line
    
def menu():
    '''菜单程序'''
    print 'Welcome to URL Manage System!'
    while True:
        order = raw_input('What do you want(help: to view help txt):')
        if order in ['add','del','cha','che','help']:
            if order == 'help':
                help()
            else:
                URL(order)
        else:
            print 'Invalid order,Please input again'
        print 'n'
        
def help():
    print '''
add:   Add
del:   Delete
cha:   Change
che:   Check
help:  Help
'''
        
if __name__ == '__main__':
    '''同目录下会生成utl.html文件,储存书签,可直接用浏览器打开'''
    menu()

第十二题:

用户名和密码.回顾练习7-5,修改代码使之可以支持"上次登录时间".请参阅time模块中的文档了解如何记录用户上次登录的时间.另外提供一个"系统管理员",它可以导出所有用户的用户名,密码(如果想要的话,你可以把密码加密),以及"上次登录时间。

以前在CSDN写过跟这个非常类似的程序,请参阅:

Python–简单的用户管理系统  传送门

第十三题:

命令行参数。写一个程序,打印出所有的命令行参数。

#-*-coding:utf-8-*-

import sys

print str(sys.argv)

关于Python命令行参数也在原Blog做过总结:

Python 命令行解析工具 Argparse介绍(一)  传送门

Python 命令行解析工具 Argparse介绍(二)  传送门

第十四题:

这段代码是在网上copy的,自己写了半天感觉有点渣,一开始思路错了,这个写的特别好,就放在这里了。

# -*- coding:utf-8 -*-
 
import sys
import os
  
def new_eval( num ):
    if num[1] == "+":  
        return int( num[0] ) + int( num[2] )  
    elif num[1] == "-":  
        return int( num[0] ) - int( num[2] )  
    elif num[1] == "*":  
        return int( num[0] ) * int( num[2] )  
    elif num[1] == "/":  
        return int( num[0] ) / int( num[2] )  
    elif num[1] == "%":  
        return int( num[0] ) % int( num[2] )  
    elif num[1] == "**":  
        return int( num[0] ) ** int( num[2] )  
    else:  
        return "error operator"  
  
if __name__ == "__main__":
    if sys.argv[1:][0] == "print":
        with open( "result.txt" ) as fobj:
            print fobj.read()
        os.remove("result.txt")
    else:
        with open( "result.txt", "a+" ) as fobj:
            fobj.write("".join(sys.argv[1:]))
            fobj.write("n")
            fobj.write( str(new_eval( sys.argv[1:] ) ))
            fobj.write("n")
        print "the result is : %d" % ( new_eval( sys.argv[1:] ) )

第十五题:

复制文件。提示输入两个文件名(或者使用命令行参数),把第一个文件的内容复制到第二个文件中去。

#-*-coding:utf-8-*-

import shutil

filename1 = raw_input('Please input first filename:')
filename2 = raw_input('Please input second filename:')
shutil.copy(filename1,filename2)

第十六题:

文本处理。人们输入的字符常常超过屏幕的最大宽度,编写一个程序,在一个文本文件中查找长度大于80个字符的文本行。从最接80个字符的单词断行,把剩余的文件插入到下一行处。程序执行完毕后,应该没有超过80个字符的文本行了。

 
一开始以为需要用到正则表达式,因为需要匹配单词边界,后来发现只要查找最靠近80的空格就好了,要保持单词的完整性,部分说明请看注释:

#-*- coding:utf-8 -*-

def check_text():
    '''文档处理函数,对长度超过80的行截断'''
    f = open('1.txt','r')
    lines_1 = f.readlines()
    f.close()
    lines_2 = []  #将新生产的文档先储存在lines_2中
    for line in lines_1:
        if len(line)>80:
            if line[80]==' ':  #如果第81个位置是空格就不需要考虑单词边界的问题
                lines_2.append(line[:80]+'n')
                lines_2.append(line[81:])
            else:
                local = line[:80].rfind(' ')  #否则查找最靠近第80个位置的空格截断,保持单词的完整性
                lines_2.append(line[:local]+'n')
                lines_2.append(line[local+1:])
        else:
            lines_2.append(line)
    f = open('1.txt','w')
    f.writelines(lines_2)
    f.close()
                
            
if __name__ == '__main__':
    '''主函数'''
    while True:  #循环检测每行的长度,直至长度全部小于或等于80
        f = open('1.txt','r')
        lines = f.readlines()
        f.close()
        for line in lines:
            if len(line)>80:
                check_text()
                break
        else:
            break
    print 'Done!'

第十七题:

文本处理。创建一个原始的文本文件编辑器,你的程序应该是菜单驱动的,有如下这些选项:

1)创建文件(提示输入文件名和任意行的文本输入)

2)显示文件(把文件的内容显示到屏幕)

3)编辑文件(提示输入要修改的行,然后让用户进行修改)

4)保存文件

5)退出

#-*- coding:utf-8 -*-

def Create():
    '''Create a new file'''
    name = raw_input('Please input file name:')
    f = open(name,'w')
    print "Please input file content,'.' to end!"
    while True:
        line = raw_input()+'n'
        if line=='.n':
            f.close()
            break
        f.write(line)

def Print():
    name = raw_input('Please input file name:')
    f = open(name)
    for line in f:
        print line
    f.close()

def Edit():
    name = raw_input('Please input file name:')
    f = open(name)
    l = int(raw_input('Witch line do you want to check:'))
    lines = f.readlines()
    f.close()
    lines[l-1] = raw_input('Please input file content:')+'n'
    f = open(name,'w')
    f.writelines(lines)
    f.close()
    
def help():
    print '''
(C)reate File
(P)rint File
(E)dit File
(Q)uit'''

if __name__=='__main__':
    print 'Welcome to File Management System!'
    help()
    while True:
        order = raw_input('What do you want:')
        if order in 'CPEQ':
            if order == 'C':
                Create()
            elif order == 'P':
                Print()
            elif order == 'E':
                Edit()
            elif order == 'Q':
                break
        else:
            continue

第十八题:

搜索文件. 提示输入一个字节值(0 – 255)和一个文件名. 显示该字符在文件中出现的次数.

#-*- coding:utf-8 -*-

def mycount():
    num = 0
    filename = raw_input('Please input file name:')
    mystring = raw_input('Please input your string:')
    f = open(filename)
    for line in f:
        num += line.count(mystring)
    return num

if __name__ == '__main__':
    stringnum = mycount()
    print stringnum

第十九题:

创建文件. 创建前一个问题的辅助程序. 创建一个随机字节的二进制数据文件, 但 某一特定字节会在文件中出现指定的次数. 该程序接受三个参数:

1) 一个字节值( 0 – 255 ),
2) 该字符在数据文件中出现的次数, 以及

3) 数据文件的总字节长度.

#-*- coding:utf-8 -*-

from random import randint

def create(filename, value, total, maxlen):
    assert 0 <= value <= 255
    ls = [chr(randint(0, 255)) for i in xrange(maxlen-total)]
    ch = chr(value)
    for i in xrange(total-ls.count(ch)):
        ls.insert(randint(0, len(ls)-1), ch)
    for i in xrange(maxlen - len(ls)):
        ls.insert(randint(0, len(ls)-1), chr(randint(0, value-1)))
    with open(filename, 'wb') as f:
        f.write(''.join(ls))
        
if __name__ == '__main__':
    filename = raw_input('file name: ')
    value = input('value: ')
    total = input('total: ')
    maxlen = input('max length of file: ')
    create(filename, value, total, maxlen)

第二十题:

压缩文件. 写一小段代码, 压缩/解压缩 gzip 或 bzip 格式的文件. 可以使用命令行下的 gzip 或 bzip2 以及 GUI 程序 PowerArchiver , StuffIt , 或 WinZip 来确认你的 Python支持这两个库.

#-*- coding:utf-8 -*-

import gzip

def encode(zipfile,otherfile):
    obj1 = open(otherfile,'rb')
    obj2 = gzip.open(zipfile,'wb')
    obj2.writelines(obj1)
    obj1.close()
    obj2.close()
    
def decode(zipfile,otherfile):
    f = gzip.open(zipfile,'rb')
    file_content = f.read()
    obj = open('zip.txt','w')
    obj.writelines(file_content)
    f.close()
    
if __name__ == '__main__':
    zipfile = raw_input('Please input zip file name:')
    otherfile = raw_input('Please input other file name:')
    encode(zipfile, otherfile)
    decode(zipfile, otherfile)

第二十一题:

ZIP 归档文件. 创建一个程序, 可以往 ZIP 归档文件加入文件, 或从中提取文件,有可能的话, 加入创建ZIP 归档文件的功能. 

#-*- coding:utf-8 -*-

import zipfile

def add_file():
    zip_name = raw_input('Please input zip file name:')
    file_name = raw_input('Please input other file name:')
    f = zipfile.ZipFile(zip_name,'a')
    f.write(file_name)
    
def read_file():
    zip_name = raw_input('Please input zip file name:')
    f = zipfile.ZipFile(zip_name,'r')
    for name in f.namelist():
        file = open(name,'w')
        file.write(f.read(name))
        file.close()
    f.close()

if __name__=='__main__':
    add_file()
    read_file()

第二十二题:

ZIP归档文件。创建一个python脚本lszip.py,使它可以显示额外信息:压缩文件大小,每个文件的压缩比率(通过压缩前后文件大小),以及完成的time.ctime()时间戳,而不是只有日期和HH:MM。

#-*- coding:utf-8 -*-

import zipfile
import os
import time
filename = raw_input('zip file name: ')
print 'zip file size: ', os.stat(filename).st_size
f = zipfile.ZipFile(filename, 'r')
print 'filenametdatetimetsizetcompress sizetrate'
for info in f.infolist():
    t = time.ctime(time.mktime(tuple(list(info.date_time) + [0, 0, 0])))
    print '%st%st%dt%dt%.2f%%' % (info.filename, t, info.file_size, info.compress_size, float(info.compress_size) / info.file_size * 100)
f.close()

第二十三题:

TAR归档文件。为TAR归档文件建立类似上个问题的程序。这两种文件的不同之处在于ZIP文件通常是压缩的,而TAR文件不是,只是在gzip和bzip2的支持下才能完成压缩工作。加入任意一种压缩格式支持。

import tarfile
import time
filename = raw_input('file name: ')
if not tarfile.is_tarfile(filename):
  print "it's not a
tarfile"
else:
  tar =
tarfile.open(filename, 'r')
  for info in tar:
    print info.name, info.size,
time.ctime(info.mtime)
  tar.close()

第二十四题:

归档文件转换。参考前两个问题的解决方案,写一个程序,在ZIP和TAR/gzip或TAR/bzip2归档文件间移动文件。文件可能是已经存在的,必要时请创建文件。

#-*- coding:utf-8 -*-

import tarfile
import zipfile
import os

def movefile(src, dst, filename):
    if src.endswith('.zip') and dst.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
        zipobj = zipfile.ZipFile(src, 'r')
        content = zipobj.read(filename)
        zipobj.close()
        
        with open(filename, 'w') as f:
            f.write(content)
        tar = tarfile.open(dst, 'r')
        ls = tar.getnames()
        tar.extractall()
        tar.close()
        
        mode = 'w:gz' if dst.endswith(('tar.gz', '.tgz')) else 'w:bz2'
        tar = tarfile.open(dst, mode)
        for name in ls+[filename]:
            tar.add(name)
            os.remove(name)
        tar.close()
    elif src.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')) and dst.endswith('.zip'):
        tar = tarfile.open(src, 'r')
        tar.extract(filename)
        tar.close()
        zipobj = zipfile.ZipFile(dst, 'a')
        zipobj.write(filename)
        zipobj.close()
        os.remove(filename)
if __name__ == '__main__':
    movefile('1.zip', '2.tar.gz', '1.txt')
    movefile('2.tar.gz', '1.zip', '2.txt')

第二十五题:

通用解压程序。创建一个程序,接受任意数目的归档文件以及一个目标目录为参数,归档文件格式可以是.zip、.tgz、.tar.gz、.gz、
bz2、.tar.bz2、.tbz中的一种或几种。程序会把第一个归档文件解压后放入目标目录,把其他归档文件解压后放入以对应文件名命名的目录下(不包括扩展名)。例如输入的文件名为header.txt.gz和data.tgz,目标目录为incoming,header.txt会被解压到incoming而data.tgz中的文件会被放入incoming/data。

#-*- coding:utf-8 -*-

import tarfile
import zipfile
import os

def decode_file(P,filename):
    if filename.endswith('.zip'):
        f = zipfile.ZipFile(P+filename,'r')
        for name in f.namelist():
            file = open(P+name,'w')
            file.write(f.read(name))
            file.close()
        f.close()
    elif filename.endswith(('.tgz', '.tar.gz', '.bz2', '.tbz', 'tar')):
        f = tarfile.open(P+filename,'r')
        f.extractall(path=P)
        f.close()
        

if __name__ == '__main__':
    path = raw_input('Please input file path:')
    name = raw_input('Please input file name:')
    decode_file(path, name)

《Python核心编程》第九章练习解析》上有 1 条评论

  1. Pingback 引用通告: 《Python核心编程》第十章练习解析 | Xman'Blog

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*