0) 引言
这几天读了《A Byte of Python》这本书,发现还真是书如其名,真的是a byte. 但是虽然本书内容极简,但是python的最基础的内容都进行了讲解(当前生成器什么的没有涉及,毕竟是byte of Python :) )。其实本质上作为python的一个最初级的入门的启蒙书籍还是非常合格的。书中只是给出了一些python的概念,一些小例子以及相应的python的基础语法,如果大家对其他的语言有过了解的话,看本书还是比较容易的。
其实一直以来,个人认为学习一门语言首先要学习一下这门语言最初级的一些语法格式,比如说控制流,基础的表达式,函数这些最基本的概念,然后掌握最基本的数据结构,比如说python中的列表,元组,字典什么的。然后是类。最后是语言的一些独特的特点,以及一些其他的高阶知识。
回到《A Byte of Python》这本书,书中在最后留了一个小问题,就是需要写一个地址簿的小程序:
创建你自己的命令行 地址簿 程序。在这个程序中,你可以添加、修改、删除和搜索你的联系人(朋友、家人和同事等等)以及它们的信息(诸如电子邮件地址和/或电话号码)。这些详细信息应该被保存下来以便以后提取。
其实这种实践的方式才是学习的最高效的方式。曾经无数次的重复一个过程,就是看过一本书后过了一段时间就完全忘记了学到的东西,然后再看,觉得记住了,然后过段时间继续忘记,周而复始。这个迭代的过程中缺少的就是多实践。因此在看完这本书后,就拿了这个例子练习一下。
1) 地址簿程序0.0.1版本
下面是地址簿程序的0.0.1版本。这个版本完全是过程式的编程,虽然定义了类Person,但是主要内容还是基于函数的过程式编程。下面是源代码,可以看到对每一个分支有一个处理函数,函数间没有过少相关性,每个函数自己load文件,自己close文件,做了大量的重复性工作。(这个版本没有经过仔细的测试,还是有一堆bug的)
import sys
import cPickle
# address book
class Person:
def __init__(self,name,phoneNum,addr):
self.name = name
self.phoneNum = phoneNum
self.addr = addr
def getName(self):
return self.name
def getPhoneNum(self):
return self.phoneNum
def getAddr(self):
return self.addr
addrBook = {}
addrBookFileName = 'AddrBook.data'
addrFile = file(addrBookFileName)
try:
addrBook = cPickle.load(addrFile)
except:
print "Maybe the addrFile is Empty!"
def addPerson():
name = raw_input("Please intut the name:")
phoneNum = raw_input("Please intut the phone number:")
addr = raw_input("Please intut the address:")
somePerson = Person(name,phoneNum,addr)
addrBook[somePerson.name]=somePerson
#print addrBook
try:
addrFile = file(addrBookFileName,'w')
cPickle.dump(addrBook,addrFile)
except:
print "There is some exception of add people."
finally:
addrFile.close()
def findPerson():
name = raw_input("Please intut the name that you want to find :")
try:
for nameFromBook,person in addrBook.items():
if nameFromBook == name:
print "the address and phoneNum of %s are %s and %s" % (name,person.getAddr(),person.getPhoneNum())
else:
print "Find nothing about %s" % name
except:
print "There is some exception of find people."
finally:
addrFile.close()
def delPerson():
name = raw_input("Please intut the name that you want to del :")
if name in addrBook:
del addrBook[name]
try:
addrFile = file(addrBookFileName,'w')
cPickle.dump(addrBook,addrFile)
print "User %s is already deleted" % name
except:
print "There is some exception of add people."
finally:
addrFile.close()
if len(sys.argv)<2:
print 'No action take'
sys.exit()
if sys.argv[1].startswith('--'):
option = sys.argv[1][2:]
if option =='add':
addPerson()
elif option == 'delete':
delPerson()
elif option == 'find':
findPerson()
elif option == 'version':
print "version 0.0.1"
else:
print 'Unknown option'
sys.exit()
2) 地址簿程序0.0.2
其实Person是一个类,那么地址簿本身也可以是一个类。这样可以在类中对所有的操作进行处理,同时可以在构造函数中load文件,在析构函数中写文件,这样可以保证对文件的操作尽可能的少。同时这样才是一个面向对象的编程应该有的态度:)
# address book
import sys
import cPickle
class Person:
def __init__(self,name,phoneNum,addr):
self.name = name
self.phoneNum = phoneNum
self.addr = addr
def getName(self):
return self.name
def getPhoneNum(self):
return self.phoneNum
def getAddr(self):
return self.addr
class addrBook:
def __init__(self,option='add'):
self.addressBook={}
self.addressBookFile = 'AddrBook.data'
self.addrFile = file(self.addressBookFile)
try:
self.addressBook = cPickle.load(self.addrFile)
except:
if option =='add':
pass
else:
print 'The addressBook is Empty.'
self.addrFile.close()
sys.exit()
finally:
self.addrFile.close()
def addPerson(self,name,addr,phoneNum):
try:
somePerson = Person(name,addr,phoneNum)
if self.addressBook.has_key(name):
print "User %s already added to the addressBook." % name
else:
self.addressBook[name] = somePerson
print "Add Person Success."
except:
print "There are some exceptions in add person."
def searchPerson(self,name):
try:
for nameFromBook,personFromBook in self.addressBook.items():
if nameFromBook == name:
print "The address and phoneNumber of %s are %s and %s."\
% (name,personFromBook.getAddr(),personFromBook.getPhoneNum())
return
print "there is no user of %s." % name
except:
print "There are some exceptions in searching person."
def delPerson(self,name):
try:
if self.addressBook.has_key(name):
del self.addressBook[name]
print "Delete Person Success."
else:
print "there is no user of %s." % name
except:
print "There are some exceptions in deleting person."
def __del__(self):
try:
self.addrFile = file(self.addressBookFile,'w')
if not self.addressBook:
pass
else:
cPickle.dump(self.addressBook,self.addrFile)
except:
print "Some exception occur when write data to file."
finally:
self.addrFile.close()
def listAllPerson(self):
try:
for nameFromBook,personFromBook in self.addressBook.items():
print "The address and phoneNumber of %s are %s and %s."\
% (nameFromBook,personFromBook.getAddr(),personFromBook.getPhoneNum())
except:
print "There are some exceptions in listing person."
helpDoc = '''All the command as follow:
python addrBook1.py --help : show help
python addrBook1.py --version : show version
python addrBook1.py --add : add user to addrBook
python addrBook1.py --del : delete user from addrBook
python addrBook1.py --search : search user from addrBook'''
def main():
if len(sys.argv)<2:
print 'No Action Occur.'
print helpDoc
sys.exit()
if sys.argv[1].startswith('--'):
option = sys.argv[1][2:]
if option=='help':
print helpDoc
sys.exit()
elif option == 'version':
print "version 0.0.2"
sys.exit()
AddrBookInst = addrBook(option)
if option == 'add':
name = raw_input("Please intut the name:")
phoneNum = raw_input("Please intut the phone number:")
addr = raw_input("Please intut the address:")
AddrBookInst.addPerson(name,phoneNum,addr)
elif option=='del':
name = raw_input("Please intut the name that you want to del :")
AddrBookInst.delPerson(name)
elif option =='search':
name = raw_input("Please intut the name that you want to search :")
AddrBookInst.searchPerson(name)
elif option == 'list': #hiden parameter :)
AddrBookInst.listAllPerson()
else:
print "Parameter wrong, please check with help."
sys.exit()
if __name__ =="__main__":
main()
其实这个程序的实现过程中函数有一些坑的,比如说为什么要在init()函数中添加option的参数呢,为何要在异常中对’add’进行处理呢?因为在类的创建的时候构造函数要打开文件(基于我们的设计),如果文件是空的话,就会抛异常,因此如过是查询操作或者删除操作,我们就应该关闭打开的连接,同时终止程序,但是但是’add’操作是必须要保证初始的文件是可以为空的,因此我们直接用了’pass’。
3)后记
没有地址簿程序0.0.3了。因为其实在这个程序上再进行迭代优化没有什么意思了。本身这就是一个比较简单的练习题。