[TOC]
為通渭等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及通渭網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站制作、做網(wǎng)站、通渭網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!? 很多初學(xué)者在了解了一門編程語言的基本語法和使用之后,面對一個’開發(fā)需求‘時仍然會覺得無從下手、沒有思路/套路,本節(jié)主題“編程范式”正是為了解決該問題,那到底什么是編程范式呢?
編程范式指的就是編程的套路,打個比方,如果把編程的過程比喻為練習(xí)武功,那編程范式指的就是武林中的各種流派,而在編程的世界里常見的流派有:面向過程、函數(shù)式、面向?qū)ο蟮?,本?jié)我們主要介紹前兩者。
? 在正式介紹前,我們需要強(qiáng)調(diào):“功夫的流派沒有高低之分,只有習(xí)武的人才有高低之分“,在編程世界里更是這樣,各種編程范式在不同的場景下都各有優(yōu)劣,誰好誰壞不能一概而論,下面就讓我們來一一解讀它們。
插圖:惡搞圖62
? ”面向過程“核心是“過程”二字,“過程”指的是解決問題的步驟,即先干什么再干什么......,基于面向過程開發(fā)程序就好比在設(shè)計一條流水線,是一種機(jī)械式的思維方式,這正好契合計算機(jī)的運(yùn)行原理:任何程序的執(zhí)行最終都需要轉(zhuǎn)換成cpu的指令流水按過程調(diào)度執(zhí)行,即無論采用什么語言、無論依據(jù)何種編程范式設(shè)計出的程序,最終的執(zhí)行都是過程式的。
插圖:惡搞圖63
? 詳細(xì)的,若程序一開始是要著手解決一個大的問題,按照過程式的思路就是把這個大的問題分解成很多個小問題或子過程去實(shí)現(xiàn),然后依次調(diào)用即可,這極大地降低了程序的復(fù)雜度。舉例如下:
? 寫一個數(shù)據(jù)遠(yuǎn)程備份程序,分三步:本地數(shù)據(jù)打包,上傳至云服務(wù)器,檢測備份文件可用性
import os,time
# 一:基于本章所學(xué),我們可以用函數(shù)去實(shí)現(xiàn)這一個個的步驟
# 1、本地數(shù)據(jù)打包
def data_backup(folder):
print("找到備份目錄: %s" %folder)
print('正在備份...')
zip_file='/tmp/backup_%s.zip' %time.strftime('%Y%m%d')
print('備份成功,備份文件為: %s' %zip_file)
return zip_file
# 2、上傳至云服務(wù)器
def cloud_upload(file):
print("\nconnecting cloud storage center...")
print("cloud storage connected")
print("upload [%s] to cloud..." %file)
link='https://www.xxx.com/bak/%s' %os.path.basename(file)
print('close connection')
return link
#3、檢測備份文件可用性
def data_backup_check(link):
print("\n下載文件: %s , 驗(yàn)證文件是否無損..." %link)
# 二:依次調(diào)用
# 步驟一:本地數(shù)據(jù)打包
zip_file = data_backup(r"/Users/egon/歐美100G高清無碼")
# 步驟二:上傳至云服務(wù)器
link=cloud_upload(zip_file)
# 步驟三:檢測備份文件的可用性
data_backup_check(link)
插圖:惡搞圖64
面向過程總結(jié):
1、優(yōu)點(diǎn)
將復(fù)雜的問題流程化,進(jìn)而簡單化
2、缺點(diǎn)
'''
程序的可擴(kuò)展性極差,因?yàn)橐惶琢魉€或者流程就是用來解決一個問題,就好比生產(chǎn)汽水的流水線無法生產(chǎn)汽車一樣,即便是能,也得是大改,而且改一個組件,與其相關(guān)的組件可能都需要修改,比如我們修改了cloud_upload的邏輯,那么依賴其結(jié)果才能正常執(zhí)行的data_backup_check也需要修改,這就造成了連鎖反應(yīng),而且這一問題會隨著程序規(guī)模的增大而變得越發(fā)的糟糕。
'''
def cloud_upload(file): # 加上異常處理,在出現(xiàn)異常的情況下,沒有l(wèi)ink返回
try:
print("\nconnecting cloud storage center...")
print("cloud storage connected")
print("upload [%s] to cloud..." %file)
link='https://www.xxx.com/bak/%s' %os.path.basename(file)
print('close connection')
return link
except Exception:
print('upload error')
finally:
print('close connection.....')
def data_backup_check(link): # 加上對參數(shù)link的判斷
if link:
print("\n下載文件: %s , 驗(yàn)證文件是否無損..." %link)
else:
print('\n鏈接不存在')
3、應(yīng)用場景
面向過程的程序設(shè)計一般用于那些功能一旦實(shí)現(xiàn)之后就很少需要改變的場景, 如果你只是寫一些簡單的腳本,去做一些一次性任務(wù),用面向過程去實(shí)現(xiàn)是極好的,但如果你要處理的任務(wù)是復(fù)雜的,且需要不斷迭代和維護(hù), 那還是用面向?qū)ο笞顬榉奖恪?/code>
插圖:惡搞圖65
函數(shù)式編程并非用函數(shù)編程這么簡單,而是將計算機(jī)的運(yùn)算視為數(shù)學(xué)意義上的運(yùn)算,比起面向過程,函數(shù)式更加注重的是執(zhí)行結(jié)果而非執(zhí)行的過程,代表語言有:Haskell、Erlang。而python并不是一門函數(shù)式編程語言,但是仍為我們提供了很多函數(shù)式編程好的特性,如lambda,map,reduce,filter
插圖:惡搞圖66
? 對比使用def關(guān)鍵字創(chuàng)建的是有名字的函數(shù),使用lambda關(guān)鍵字創(chuàng)建則是沒有名字的函數(shù),即匿名函數(shù),語法如下
lambda 參數(shù)1,參數(shù)2,...: expression
舉例
# 1、定義
lambda x,y,z:x+y+z
#等同于
def func(x,y,z):
return x+y+z
# 2、調(diào)用
# 方式一:
res=(lambda x,y,z:x+y+z)(1,2,3)
# 方式二:
func=lambda x,y,z:x+y+z # “匿名”的本質(zhì)就是要沒有名字,所以此處為匿名函數(shù)指定名字是沒有意義的
res=func(1,2,3)
插圖:惡搞圖67
匿名函數(shù)與有名函數(shù)有相同的作用域,但是匿名意味著引用計數(shù)為0,使用一次就釋放,所以匿名函數(shù)用于臨時使用一次的場景,匿名函數(shù)通常與其他函數(shù)配合使用,我們以下述字典為例來介紹它
salaries={
'siry':3000,
'tom':7000,
'lili':10000,
'jack':2000
}
要想取得薪水的大值和最小值,我們可以使用內(nèi)置函數(shù)max和min(為了方便開發(fā),python解釋器已經(jīng)為我們定義好了一系列常用的功能,稱之為內(nèi)置的函數(shù),我們只需要拿來使用即可)
>>> max(salaries)
'tom'
>>> min(salaries)
'jack'
內(nèi)置max和min都支持迭代器協(xié)議,工作原理都是迭代字典,取得是字典的鍵,因而比較的是鍵的大和最小值,而我們想要的是比較值的大值與最小值,于是做出如下改動
# 函數(shù)max會迭代字典salaries,每取出一個“人名”就會當(dāng)做參數(shù)傳給指定的匿名函數(shù),然后將匿名函數(shù)的返回值當(dāng)做比較依據(jù),最終返回薪資高的那個人的名字
>>> max(salaries,key=lambda k:salaries[k])
'lili'
# 原理同上
>>> min(salaries,key=lambda k:salaries[k])
'jack'
同理,我們直接對字典進(jìn)行排序,默認(rèn)也是按照字典的鍵去排序的
>>> sorted(salaries)
['jack', 'lili', 'siry', 'tom']
插圖:惡搞圖68
函數(shù)map、reduce、filter都支持迭代器協(xié)議,用來處理可迭代對象,我們以一個可迭代對象array為例來介紹它們?nèi)齻€的用法
array=[1,2,3,4,5]
要求一:對array的每個元素做平方處理,可以使用map函數(shù)
map函數(shù)可以接收兩個參數(shù),一個是函數(shù),另外一個是可迭代對象,具體用法如下
>>> res=map(lambda x:x**2,array)
>>> res
解析:map會依次迭代array,得到的值依次傳給匿名函數(shù)(也可以是有名函數(shù)),而map函數(shù)得到的結(jié)果仍然是迭代器。
>>> list(res) #使用list可以依次迭代res,取得的值作為列表元素
[1, 4, 9, 16, 25]
插圖:惡搞圖69
要求二:對array進(jìn)行合并操作,比如求和運(yùn)算,這就用到了reduce函數(shù)
reduce函數(shù)可以接收三個參數(shù),一個是函數(shù),第二個是可迭代對象,第三個是初始值
# reduce在python2中是內(nèi)置函數(shù),在python3中則被集成到模塊functools中,需要導(dǎo)入才能使用
>>> from functools import reduce
>>> res=reduce(lambda x,y:x+y,array)
>>> res
15
解析:
1 沒有初始值,reduce函數(shù)會先迭代一次array得到的值作為初始值,作為第一個值數(shù)傳給x,然后繼續(xù)迭代一次array得到的值作為第二個值傳給y,運(yùn)算的結(jié)果為3
2 將上一次reduce運(yùn)算的結(jié)果作為第一個值傳給x,然后迭代一次array得到的結(jié)果作為第二個值傳給y,依次類推,知道迭代完array的所有元素,得到最終的結(jié)果15
也可以為reduce指定初始值
>>> res=reduce(lambda x,y:x+y,array,100)?>>> res
115
要求三:對array進(jìn)行過濾操作,這就用到了filter函數(shù),比如過濾出大于3的元素
>>> res=filter(lambda x:x>3,array)
解析:filter函數(shù)會依次迭代array,得到的值依次傳給匿名函數(shù),如果匿名函數(shù)的返回值為真,則過濾出該元素,而filter函數(shù)得到的結(jié)果仍然是迭代器。
>>> list(res)
[4, 5]
提示:我們介紹map、filter、reduce只是為了帶大家了解函數(shù)式編程的大致思想,在實(shí)際開發(fā)中,我們完全可以用列表生成式或者生成器表達(dá)式來實(shí)現(xiàn)三者的功能。
插圖:惡搞圖70
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。