函数能够带来最大化的代码重用和最小化的代码冗余。 精心设计的函数不仅可以提高程序的健壮性,还可以增强可读性、减少维护成本。先来看以下示例代码:
def SendContent (ServerAdr, PagePath, StartLine, EndLine, sender, receiver, smtpserver, username,password):
http.httplib.HTTP(ServerAdr)
http,putrequest ("GET", PagePath)
http.putheader('Accept','text/html')
http.putheader('Accept', 'text/plain')
http.endheaders()
httpcode, httpmsg, headers = http.getreply()
if httpcode != 200:raise "Could not get document: Check URL and Path."
doc = http.getfile ()
data = doc.read()
doc.close()
lstr=data.splitlines()
j=0
for i in lstr:
j=j + 1
if i.strip () == StartLine: slice_start=j #find slice start:
elif i.strip()== EndLine : slice_end=j #find slice end
subject = "Contented get from the web"
msg = MIMEText(string.join(lstr[slice_start:slice_end]),' plain ' , 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')
smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login (username, password)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
函数 SendContent
要的作用是抓取网页中固定的内容,然后将其发送给用户。
代码本身并不复杂,但足以说明一些问题。先思考一下:到底有什么不是之处?
能否进一步改进?怎样才能做到一目了然呢? 一般来说函数设计有以下基本原则可以参考:
原则1 函数设计要尽量短小,嵌套层次不宜过深。
所谓短小,就是跟前面所提到的一样尽量避免过长函数,因为这样不需要上下拉动滚动条就能获得整体感观,
而不是来回翻动屏幕去寻找某个变量或者某条逻辑判断等。
函数中需要用到 if
、 elif
、 while
、 for
等循环语句的地方,尽量不要嵌套过深,
最好能控制在3层以内。相信很多人有过这样的经历:为了弄清楚哪段代码属于内部嵌套,
哪段属于中间层次的嵌套,哪段属于更外一层的嵌套所花费的时间比读代码细节所用时间更多。
原则2 函数申明应该做到合理、简单、易于使用。
除了函数名能够正确反映其大体功能外,参数的设计也应该简洁明了,参数个数不宜太多。 参数太多带来的弊端是:调用者需要花费更多的时间去理解每个参数的意思, 测试人员需要花费更多的精力来设计测试用例, 以确保参数的组合能够有合理的输出, 这使其测试的难度大大增加。因此函数参数设计最好经过深思熟虑。
原则3 函数参数设计应该考虑向下兼容。
实际工作中可能面临这样的情况:随着需求的变更和版本的升级, 在前一个版本中设计的函数可能需要进行一定的修改才能满足这个版本的要求。 因此在设计过程中除了着眼当前的需求还得考虑向下兼容。如以下示例:
def readfile (filename):
print ("file read completed")
readfile ("index.txt")
file read completed
import logging
def readfile (filename,logger):
print ("file read completed")
readfile('index.txt','')
file read completed
上面的代码是相同功能的函数不同版本的实观,唯一不同的是在更高级的版本中为了便于内部维护加入了日志处理, 但这样的变动却导致程序中函数调用的接口发生了改变。 这并不是最佳设计,更好的方法是通过加入默认参数来避免这种退化,做到向下兼容。 上例可以将第一行代码修改为:
import logging
def readfile (filename, logger=logging.info):
print ("file read completed")
readfile('index.txt')
file read completed
def GetContent(ServerAdr,PagePath):
http.httplib.HTTP(ServerAdr)
http,putrequest ("GET", PagePath)
http.putheader('Accept','text/html')
http.putheader('Accept', 'text/plain')
http.endheaders()
httpcode, httpcnsg, headers = http.getreply()
if httpcode != 200:
raise "Could not get document: Check CJRL and Path."
doc = http.getfile ()
data = doc . read ()# read file
doc.close()
return data
def ExtractData(inputstring, start_line, end_line):
lstr=inputstring.splitlines()
j=0
for i in lstrs:
j=j+1
if i.strip() == start_line: slice_start=j
elif i.strip() == end_line: slice_end=j
return lstr[slice_start:slice_end]
def SendEmail(sender, receiver,smtpsever,username, password, content):
subject = "Contented get from the web"
mag = MIMEText(content,'plain','utf-8')
msg[' Subject'] = Header(subject, 'utf-8 ')
smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login (username, password)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
Python中函数设计的好习惯还包括:不要在函数中定义可变对象作为默认值, 使用异常替换返回错误,保证通过单元测试等。