Python 代碼優化實踐
Usage: demo.py [sourcedir]
Usage: demo.py [sourcedir] bydir
第一種調用的實際操作是:讀取特定應用程序目錄所有文件,並獲取全路徑作為一個集合,再把參數文件夾中文件按文件名與集合中文件進行匹配,如果匹配上則執行替換操作。
第二種調用的實際操作是:按參數文件夾的目錄存放的路徑,完整替換到應用程序的對應目錄。
下面是最初的代碼實現:
#執行本地文件替換的具體操作 def ReplaceLocalFiles(filepath, context, filecontext, softpath, bydir): if (":" not in filepath) or (not os.path.isdir(filepath)): printandwritelog(u"目標路徑有誤,請確認是目錄後再重試") return "error" fileList = os.walk(filepath) for root, dirs, files in fileList: for file in files: if bydir:#如果按目錄進行替換的話走下面這個邏輯分支 filefullpath = os.path.join(root, file) targetfullpath = filefullpath.replace(filepath, softpath) shutil.copy2(filefullpath, targetfullpath) printandwritelog(u"文件 %s 拷貝到 %s 成功" % (filefullpath, targetfullpath)) else:#如果自行查找文件路徑進行替換的話先走下這個邏輯分支 filecounts = checkcount(file, filecontext) if (0 == filecounts): printandwritelog(u"沒有找到文件%s的路徑,請使用指定路徑方式進行替換" % file) continue elif (1 < filecounts): printandwritelog(u"文件 %s 有 %s 個路徑,請使用指定路徑方式進行替換" % (file , filecounts)) continue elif (1 == filecounts): for line in context.split("\n"): filename = line.split("\\")[-1] if file == filename: os.rename(line , line + str(random.randint(0, 100))) shutil.copy2(os.path.join(root, file), line) printandwritelog(u"文件 %s 拷貝到 %s 成功" % (os.path.join(root, file), line)) else: printandwritelog(u"替換文件個數有誤%s" % file) #判斷如果是本地文件則直接調用替換函數,如果是網絡路徑,則先下載文件再替換 def RelpaceFiles(filepath, context, filecontext, softpath, bydir): if ":" in filepath: printandwritelog(u"提供的本地路徑,走本地路徑文件替換流程") ReplaceLocalFiles(filepath, context, filecontext, softpath, bydir) else: printandwritelog(u"提供的FTP路徑,先下載文件到本地後再執行替換流程") sourceFileDir = cur_file_dir() + r"\testdir" if os.path.isdir(sourceFileDir): shutil.rmtree(sourceFileDir) obj = netutilex.SFTP("192.168.1.100", "test", "testpwd") obj.syncSftpDir(filepath, sourceFileDir) obj.close() ReplaceLocalFiles(sourceFileDir, context, filecontext, softpath, bydir) #先處理替換前的前置操作,環境準備好之後執行替換操作 def ReplaceAllFiles(filepath, bydir): softpath = checkinst() if ("notinst" == softpath): printandwritelog(u"沒有檢測到衛士安裝目錄,請確認後重試") return "error" else: context, filecontext = getallfiles(softpath) RelpaceFiles(filepath, context, filecontext, softpath, bydir)
先簡單說明下各函數的功能:
ReplaceLocalFiles:主要功能函數,實現具體的替換操作;
RelpaceFiles:根據傳入參數判斷是否是網絡路徑,如果是則先把文件下載到本地,然後調用ReplaceLocalFiles執行替換操作;
ReplaceAllFiles:做了一些環境準備的事情,然後調用實際的功能函數RelpaceFiles進行幹活;
printandwritelog:記錄日誌並輸出;
checkinst:檢查目標程序是否安裝,如果安裝則返回安裝路徑;
getallfiles:獲取目標應用程序的文件全路徑集合;
checkcount:獲取指定文件名在目標應用程序文件集合中出現的次數netutilex:一個獨立的操作SFTP的庫文件。
從目前的代碼中能發現至少有2個地方可以優化:
- 函數之間需要傳遞的參數太多了,可以看看是否全部必要,考慮下如何精簡;
- 部分業務邏輯太細化,有重復的代碼實現,導致實現看起來比較臃腫。
對於第1點,優化的思路是:對於非所有函數都必須調用的參數,盡可能的固化到實際使用的函數中,避免各函數僅僅做了傳遞員的工作。
對於第2點,優化的思路是:合並同類項,對於重復代碼的部分,盡可能提取到共用邏輯中實現。
下面是優化後的代碼:
#執行本地文件替換的具體操作 def ReplaceLocalFiles(filepath, bydir): if (":" not in filepath) or (not os.path.isdir(filepath)): printandwritelog(u"目標路徑有誤,請確認是合法目錄後重試") return "error" softpath = checkinst() if ("notinst" == softpath): printandwritelog(u"沒有獲取到目標軟件安裝目錄,請確認後重試") return "error" context, filecontext = getallfiles(softpath) fileList = os.walk(filepath) for root, dirs, files in fileList: for file in files: filefullpath = os.path.join(root, file) targetfullpath = filefullpath.replace(filepath, softpath) if not bydir:#如果自行查找文件路徑進行替換的話先走下這個邏輯分支 filecounts = checkcount(file, filecontext) if (0 == filecounts): printandwritelog(u"沒有找到文件%s的路徑,請使用指定路徑方式進行替換" % file) continue elif (1 < filecounts): printandwritelog(u"文件 %s 有 %s 個路徑,請使用指定路徑方式進行替換" % (file , filecounts)) continue elif (1 == filecounts): for line in context.split("\n"): filename = line.split("\\")[-1] if file == filename: targetfullpath = line else: printandwritelog(u"替換文件個數有誤%s" % file) if os.path.isfile(targetfullpath): randomend = random.randint(0, 100) os.rename(targetfullpath , targetfullpath + str(randomend)) shutil.copy2(filefullpath, targetfullpath) printandwritelog(u"文件 %s 拷貝到 %s 成功" % (filefullpath, targetfullpath)) #先處理替換前的前置操作,環境準備好之後執行替換操作 def ReplaceAllFiles(filepath, bydir): sourceFileDir = filepath if ":" in filepath: printandwritelog(u"提供的本地路徑,走本地路徑文件替換流程") else: printandwritelog(u"提供的FTP路徑,先下載文件到本地後再執行替換流程") sourceFileDir = cur_file_dir() + r"\testdir" if os.path.isdir(sourceFileDir): shutil.rmtree(sourceFileDir) obj = netutilex.SFTP("192.168.1.100", "test", "testpwd") obj.syncSftpDir(filepath, sourceFileDir) obj.close() ReplaceLocalFiles(sourceFileDir, bydir)
具體的優化操作有:
把函數checkinst和getallfiles的調用實現放到了其返回值使用者ReplaceLocalFiles的函數體內,減少了2個參數的多次傳遞;
把函數ReplaceLocalFiles中具體的copy2操作進行了提取,因為bydir和非bydir最終都會走到這個操作;
把函數ReplaceFiles中對函數ReplaceLocalFiles的操作進行了提取,同時把函數ReplaceAllFiles和ReplaceFiles進行了合並。
優化後的結果看起來有沒有清爽很多?
Python 代碼優化實踐