日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

动态语言的灵活性是把双刃剑 -- 以Python语言为例

發(fā)布時間:2023/11/27 生活经验 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态语言的灵活性是把双刃剑 -- 以Python语言为例 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文有些零碎,總題來說,包括兩個問題:

(1)可變對象(最常見的是list dict)被意外修改的問題,

(2)對參數(shù)(parameter)的檢查問題。

這兩個問題,本質(zhì)都是因為動態(tài)語言(動態(tài)類型語言)的特性造成了,動態(tài)語言的好處就不細(xì)說了,本文是要討論因為動態(tài)--這種靈活性帶來的一些問題。

什么是動態(tài)語言(Dynamic Programming language)呢,是相對于靜態(tài)語言而言,將很多靜態(tài)語言編譯(compilation)時期所做的事情推遲到運行時,在運行時修改代碼的行為,比如添加新的對象和函數(shù),修改既有代碼的功能,改變類型。

絕大多數(shù)動態(tài)語言都是動態(tài)類型(Dynamic Typed),所謂動態(tài)類型,是在運行時確定數(shù)據(jù)類型,變量使用之前不需要類型聲明,通常變量的類型是被賦值的那個值的類型。Python就是屬于典型的動態(tài)語言。

動態(tài)語言的魅力在于讓開發(fā)人員更好的關(guān)注需要解決的問題本身,而不是冗雜的語言規(guī)范,也不用干啥都得寫個類。運行時改變代碼的行為也是非常有用,比如python的熱更新,可以做到不關(guān)服務(wù)器就替換代碼的邏輯,而靜態(tài)語言如C++就很難做到這一點。筆者使用得最多的就是C++和Python,C++中的一些復(fù)雜的點,比如模板(泛型編程)、設(shè)計模式(比如template method),在Python中使用起來非常自然。我也看到過有一些文章指出,設(shè)計模式往往是特定靜態(tài)語言的補丁 -- 為了彌補語言的缺陷或者限制。

以筆者的知識水平,遠(yuǎn)遠(yuǎn)不足以評價動態(tài)語言與靜態(tài)語言的優(yōu)劣。本文也只是記錄在我使用Python這門動態(tài)語言的時候,由于語言的靈活性,由于動態(tài)類型,踩過的坑,一點思考,以及困惑。

?

第一個問題:Mutable對象被誤改

這個是在線上環(huán)境出現(xiàn)過的一個BUG

事后說起來很簡單,服務(wù)端數(shù)據(jù)(放在dict里面的)被意外修改了,但查證的時候也花了許多時間,偽代碼如下:

?

?

上述的代碼很簡單,dct是一個dict,極大概率會調(diào)用一個不用修改dct的子函數(shù),極小概率出會調(diào)用到可能修改dct的子函數(shù)。問題就在于,調(diào)用routine函數(shù)的參數(shù)是服務(wù)端全局變量,理論上是不能被修改的。當(dāng)然,上述的代碼簡單到一眼就能看出問題,但在實際環(huán)境中,調(diào)用鏈有七八層,而且,在routine這個函數(shù)的doc里面,聲明不會修改dct,該函數(shù)本身確實沒有修改dct,但調(diào)用的子函數(shù)或者子函數(shù)的子函數(shù)沒有遵守這個約定。

?

從python語言特性看這個問題

本小節(jié)解釋上面的代碼為什么會出問題,簡單來說兩點:dict是mutable對象; dict實例作為參數(shù)傳入函數(shù),然后被函數(shù)修改了。

  Python中一切都是對象(evething is object),不管是int str dict 還是類。比如?a =5,?5是一個整數(shù)類型的對象(實例);那么a是什么,a是5這個對象嗎? 不是的,a只是一個名字,這個名字暫時指向(綁定、映射)到5這個對象。b = a??是什么意思呢,?是b指向a指向的對象,即a, b都指向整數(shù)5這個對象

  那么什么是mutable 什么是immutable呢,mutable是說這個對象是可以修改的,immutable是說這個對象是不可修改的(廢話)。還是看Python官方怎么說的吧

Mutable objects can change their value but keep their?id().

  Immutable:An object with a fixed value. Immutable objects include numbers, strings and tuples. Such an object cannot be altered. A new object has to be created if a different value has to be stored. They play an important role in places where a constant hash value is needed, for example as a key in a dictionary.

承接上面的例子(a = 5),int類型就是immutable,你可能說不對啊,比如對a賦值,?a=6, 現(xiàn)在a不是變成6了嗎?是的,a現(xiàn)在"變成"6了,但本質(zhì)是a指向了6這個對象 -- a不再指向5了

  檢驗對象的唯一標(biāo)準(zhǔn)是id,id函數(shù)返回對象的地址,每個對象在都有唯一的地址。看下面兩個例子就知道了

>>>?a?=?5;id(a)

  35170056

  >>>?a?=?6;id(a)

  35170044

?

  >>>?lst?=?[1,2,3];?id(lst)

  39117168

  >>>?lst.append(4);?id(lst)

  39117168

或者這么說,對于非可變對象,在對象的生命周期內(nèi),沒有辦法改變對象所在內(nèi)存地址上的值。

  python中,不可變對象包括:int,?long,?float,?bool,?str,?tuple,?frozenset;而其他的dict list 自定義的對象等屬于可變對象。注意: str也是不可變對象,這也是為什么在多個字符串連接操作的時候,推薦使用join而不是+

  而且python沒有機制,讓一個可變對象不可被修改(此處類比的是C++中的const)

?

dict是可變對象!

那在python中,調(diào)用函數(shù)時的參數(shù)傳遞是什么意思呢,是傳值、傳引用?事實上都不正確,我不清楚有沒有專業(yè)而統(tǒng)一的說法,但簡單理解,就是形參(parameter)和實參(argument)都指向同一個對象,僅此而已。來看一下面的代碼:

?

可以看到,剛進(jìn)入子函數(shù)double的時候,a,v指向的同一個對象(相同的id)。對于test int的例子,v因為v*=2,指向了另外一個對象,但對實參a是沒有任何影響的。對于testlst的時候,v*=2是通過v修改了v指向的對象(也是a指向的對象),因此函數(shù)調(diào)用完之后,a指向的對象內(nèi)容發(fā)生了變化。

?

如何防止mutable對象被函數(shù)誤改:

為了防止傳入到子函數(shù)中的可變對象被修改,最簡單的就是使用copy模塊拷貝一份數(shù)據(jù)。具體來說,包括copy.copy, copy.deepcopy, 前者是淺拷貝,后者是深拷貝。二者的區(qū)別在于:

簡單來說,深拷貝會遞歸拷貝,遍歷任何compound object然后拷貝,例如:

>>> lst = [1, [2]]
  >>> import copy
  >>> lst1 = copy.copy(lst)
  >>> lst2 = copy.deepcopy(lst)
  >>> print id(lst[1]), id(lst1[1]), id(lst2[1])
  4402825264 4402825264 4402988816
  >>> lst[1].append(3)
  >>> print lst, lst1,lst2
  [1, [2, 3]] [1, [2, 3]] [1, [2]]

?

從例子可以看出淺拷貝的局限性,Python中,對象的基本構(gòu)造也是淺拷貝,例如 dct = {1: [1]}; dct1 = dict(dct)

  正是由于淺拷貝與深拷貝本質(zhì)上的區(qū)別,二者性能代價差異非常之大,即使對于被拷貝的對象來說毫無差異:

?

?

在上面的示例中,dct這個dict的values都是int類型,immutable對象,因為無論淺拷貝 深拷貝效果都是一樣的,但是耗時差異巨大。如果在dct中存在自定義的對象,差異會更大

  那么為了安全起見,應(yīng)該使用深拷貝;為了性能,應(yīng)該使用淺拷貝。如果compound object包含的元素都是immutable,那么淺拷貝既安全又高效,but,對于python這種靈活性極強的語言,很可能某天某人就加入了一個mutable元素。

?

第二個問題:參數(shù)檢查

上一節(jié)說明沒有簽名 對 函數(shù)調(diào)用者是多么不爽,而本章節(jié)則說明沒有簽名對函數(shù)提供者有多么不爽。沒有類型檢查真的蛋疼,我也遇到過有人為了方便,給一個約定是int類型的形參傳入了一個int的list,而可怕的是代碼不報錯,只是表現(xiàn)不正常。

def func(arg): ? ? 
?if arg: ? ? ? ?
? ?print 'do lots of things here' ? ?
?else: ? ? ? ?
? ?print 'do anothers'

上述的代碼很糟糕,根本沒法“望名知意”,也看不出有關(guān)形參 arg的任何信息。但事實上這樣的代碼是存在的,而且還有比這更嚴(yán)重的,比如掛羊頭賣狗肉。

  這里有一個問題,函數(shù)期望arg是某種類型,是否應(yīng)該寫代碼判斷呢,比如:isinstance(arg, str)。因為沒有編譯器靜態(tài)來做參數(shù)檢查,那么要不要檢查,如何檢查就完全是函數(shù)提供者的事情。如果檢查,那么影響性能,也容易違背python的靈活性 -- duck typing; 不檢查,又容易被誤用。

  但在這里,考慮的是另一個問題,看代碼的第二行:?if arg。python中,幾乎是一切對象都可以當(dāng)作布爾表達(dá)式求值,即這里的arg可以是一切python對象,可以是bool、int、dict、list以及任何自定義對象。不同的類型為“真”的條件不一樣,比如數(shù)值類型(int float)非0即為真;序列類型(str、list、dict)非空即為真;而對于自定義對象,在python2.7種則是看是否定義了__nonzero__ 、__len__,如果這兩個函數(shù)都沒有定義,那么實例的布爾求值一定返回真。


?

總結(jié)

以上兩個問題,是我使用Python語言以來遇到的諸多問題之二,也是我在同一個地方跌倒過兩次的問題。Python語言以開發(fā)效率見長,但是我覺得需要良好的規(guī)范才能保證在大型線上項目中使用。而且,我也傾向于假設(shè):人是不可靠的,不會永遠(yuǎn)遵守擬定的規(guī)范,不會每次修改代碼之后更新docstring ...

  因此,為了保證代碼的可持續(xù)發(fā)展,需要做到以下幾點

  第一:擬定并遵守代碼規(guī)范

  代碼規(guī)范最好在項目啟動時就應(yīng)該擬定好,可以參照PEP8和google python styleguild。很多時候風(fēng)格沒有優(yōu)劣之說,但是保證項目內(nèi)的一致性很重要。并保持定期review、對新人review!

  第二:靜態(tài)代碼分析

  只要能靜態(tài)發(fā)現(xiàn)的bug不要放到線上,比如對參數(shù)、返回值的檢查,在python3.x中可以使用注解(Function?Annotations),python2.x也可以自行封裝decorator來做檢查。對代碼行為,既可以使用Coverity這種高大上的商業(yè)軟件,或者王垠大神的Pysonar2,也可以使用ast編寫簡單的檢查代碼。

  第三:單元測試

  單元測試的重要性想必大家都知道,在python中出了官方自帶的doctest、unittest,還有許多更強大的框架,比如nose、mock。

  第四:100%的覆蓋率測試

  對于python這種動態(tài)語言,出了執(zhí)行代碼,幾乎沒有其他比較好的檢查代碼錯誤的手段,所以覆蓋率測試是非常重要的。可以使用python原生的sys.settrace、sys.gettrace,也可以使用coverage等跟更高級的工具。

原文出處:http://www.cnblogs.com/xybaby/p/7208496.html

?



?

識別圖中二維碼,領(lǐng)取python全套視頻資料

轉(zhuǎn)載于:https://www.cnblogs.com/IT-Scavenger/p/9642558.html

總結(jié)

以上是生活随笔為你收集整理的动态语言的灵活性是把双刃剑 -- 以Python语言为例的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。