• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            歲月流轉(zhuǎn),往昔空明

            C++博客 首頁 新隨筆 聯(lián)系 聚合 管理
              118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks
            最近由于老板需要做一個(gè)基于ArcGIS的地理分析工具。
            經(jīng)過分析權(quán)衡,最終選用了Python作為開發(fā)語言,開發(fā)出的工具將在ArcToolbox中運(yùn)行。
            由于需要存在比較復(fù)雜的用戶交互,ArcToolbox自帶的界面無法滿足需求,因此使用了PyQt做用戶界面。

            這差不多還是我頭一次用腳本開發(fā)一個(gè)完整的應(yīng)用。麻雀雖小(就數(shù)千行代碼),但也五臟俱全。
            此帖就來總結(jié)一下做這個(gè)工具的某些經(jīng)驗(yàn)教訓(xùn)。
            一方面是自我總結(jié),一方面也希望給各位迄今為止沒用腳本干過大程序的靜態(tài)語言擁躉的筒子們以微不足道的啟發(fā)。

            先來討論一下設(shè)計(jì)上的差異。
            說到設(shè)計(jì),便會(huì)討論到設(shè)計(jì)模式。
            對(duì)于設(shè)計(jì)模式的經(jīng)典圖書《Design Patterns》而言,它所提出的模式基本是針對(duì)靜態(tài)語言,有關(guān)設(shè)計(jì)模式的實(shí)現(xiàn)方案的討論,也多半是針對(duì)C++一類的強(qiáng)類型靜態(tài)語言。在Python的開發(fā)過程中,會(huì)發(fā)現(xiàn)很多模式(或者其它的慣用手法)在原有實(shí)現(xiàn)的基礎(chǔ)上有不小的變化,甚至一些原則也有所變動(dòng)。

            最典型的例子是,在C++中,會(huì)提倡使用接口繼承而不是實(shí)現(xiàn)繼承;實(shí)現(xiàn)繼承改由委托來完成等一系列原則。
            原先在C++中用接口繼承來分割接口與實(shí)現(xiàn),在Python中,可以完全不使用繼承,而采用動(dòng)態(tài)類型的特性,以類似于運(yùn)行期Concept的方式達(dá)到接口的目的;

            相對(duì)的,繼承盡管也用于設(shè)計(jì)中,但是更主要的是以extend這樣的方式對(duì)原有的類進(jìn)行功能擴(kuò)展,使得行為類似于decorator模式;減少擴(kuò)展所需要的代碼量。

            同時(shí),python不支持重載(因?yàn)槎际莿?dòng)態(tài)類型,也確實(shí)沒法重載),如果想重載只能在函數(shù)體中用instance of這樣的函數(shù)進(jìn)行判斷并手工分派(你拿字典分派也是手工分派),至少我目前只知道這個(gè)辦法。為了避免不必要的錯(cuò)誤,建議大家還是用命名對(duì)多個(gè)重載函數(shù)顯示的區(qū)分,對(duì)于需要重載的構(gòu)造函數(shù),還是用Factory Method比較好。

            關(guān)于重構(gòu),如果腳本沒有對(duì)應(yīng)的測(cè)試,一定不要重構(gòu)。對(duì)于靜態(tài)語言,這一條件要稍顯寬松,但是在Python這樣的動(dòng)態(tài)語言上,就連Rename這樣的小型重構(gòu),都需要測(cè)試的保證,因?yàn)閹缀跛械腻e(cuò)誤只有在運(yùn)行期才能被檢定出來。

            其次,說一下代碼編寫的問題。
            和C++相比,Python是很節(jié)省代碼的。一方面要?dú)w功于語言機(jī)制,另一方面,Python豐富多樣的標(biāo)準(zhǔn)庫也為我們節(jié)省了不少的代碼量。
            先來說說語言機(jī)制。

            python一個(gè)很好的地方,就在于它將list、tuple、set、map/dict作為了build-in的要素,python的語法為這些要素提供了first class的支持。這使得我們?cè)诰帉懭萜飨嚓P(guān)操作時(shí)可以非常的方便。通常程序中大量存在類似的操作,在靜態(tài)語言中大量的語句可以在python中一句概括;在實(shí)際的編碼過程中,一定要靈活運(yùn)用Python容器操作,寫出干凈利落的代碼。

            其二就是動(dòng)態(tài)類型也讓我們不需要為類型約束填寫過多的代碼,比如不必要的繼承與接口定義。這些代碼的節(jié)省其實(shí)是很可觀的。

            其三,lambda、可調(diào)用體(其實(shí)就是仿函數(shù))被語言機(jī)制直接支持,也是能節(jié)省大量代碼的重要因素。憑借仿函數(shù),可以寫出大量在C++中難以編寫出的簡(jiǎn)潔優(yōu)雅的代碼。雖然boost費(fèi)勁心思提供了functor與lambda,但是這些庫編譯之慢,調(diào)試之辛苦,相比大家都是有感觸的。

            個(gè)人體會(huì):
            首先,靈活運(yùn)用語法優(yōu)勢(shì),特別是一些通用的初始化格式,以及一些特殊的寫法,比如list的構(gòu)造格式,slice等。這點(diǎn)往往也是腳本和靜態(tài)語言相比最大的優(yōu)勢(shì)。
            其次靈活運(yùn)用內(nèi)建函數(shù)。內(nèi)建函數(shù)往往最能發(fā)揮語法優(yōu)勢(shì),甚至可以填補(bǔ)一些語法上的空缺。個(gè)人印象最深的,要數(shù)map/reduce/zip/lambda這幾個(gè)函數(shù)/語言機(jī)制。這些東西運(yùn)用好了,能很大程度上簡(jiǎn)化本來復(fù)雜的循環(huán)代碼。當(dāng)然,對(duì)于多層循環(huán)而言,個(gè)人不太建議用嵌套的map一類的函數(shù),外層的還是展開寫可讀性比較強(qiáng),內(nèi)層則保留以簡(jiǎn)化結(jié)構(gòu);
            同時(shí)我也不太愿意用大量的lambda函數(shù),因?yàn)閘ambda函數(shù)本身很占版面,用多了代碼不那么好讀。必要的時(shí)候,還是用def定義出去比較好了。可調(diào)用體用恰當(dāng)了,能簡(jiǎn)化代碼,但是用的太多或者用法不好,也會(huì)影響可讀性。
            同時(shí),python對(duì)于內(nèi)建類型的模擬做的很好,它提供了一系列buildin function的重寫方法,可以達(dá)到完全亂真的目的,這一點(diǎn)做的比C++還要好。
            常規(guī)的內(nèi)建函數(shù)就不討論了,Python的Ref上都有。
            討論一下__getattr__, __setattr__這兩個(gè)函數(shù)。如果我們用getattr函數(shù),或者XXX.xxx這樣的方法取得對(duì)象的一個(gè)成員,python首先會(huì)到對(duì)象內(nèi)建的屬性字典中查找。如果找不到,要么raise一個(gè)exception出來,如果重寫了__getattr__,那就調(diào)用這個(gè)函數(shù)。因此這兩個(gè)函數(shù)實(shí)際上是實(shí)現(xiàn)了屬性get/set的掛鉤。一般來說,我用get/set都不是為了單純的get/set,實(shí)際上是為了保持對(duì)象內(nèi)部的一致性,訪問的安全性,細(xì)節(jié)的封裝性等等目的,不同的屬性不是那么容易就用同樣的邏輯代碼。
            本來像C#那樣為每個(gè)屬性提供獨(dú)立的get/set其實(shí)挺好的。Python則把所有的成員的get/set都攏到一起了。如果存取的附加代碼稍有差異,就容易寫出if...elif...elif...else這樣的分支代碼。
            對(duì)這個(gè)問題,我是這樣做,屬性對(duì)應(yīng)的成員變量放入字典中;每個(gè)需要做復(fù)雜存取操作的屬性,有一個(gè)存取函數(shù),存取操作的區(qū)別用if分開,屬性與存取函數(shù),則用一個(gè)字典來關(guān)聯(lián)。這樣,attr函數(shù)首先訪問存取函數(shù)的字典,按照需要執(zhí)行存取操作。如果屬性不對(duì)應(yīng)存取函數(shù),那么就直接訪問屬性字典。
            對(duì)于查找不到的情況,建議先捕獲異常,然后仿照的內(nèi)建的屬性訪問異常拋出。
            當(dāng)然,有時(shí)候我也完全不用屬性,直接使用get/set函數(shù)的形式。不過這樣的話還是不如屬性來的方便。況且有時(shí)候括號(hào)漏寫了,代碼直接就來個(gè)運(yùn)行期異常,也是挺郁悶的。
            最后討論下私有函數(shù)。對(duì)于python來說不存在真正的私有函數(shù),一般來講,要表達(dá)“私有實(shí)現(xiàn)”都是用“_”開頭的命名約定。

            最后,討論一下調(diào)試和測(cè)試。
            恐怕保證程序的正確性上,腳本還是要比靜態(tài)語言難。缺乏靜態(tài)檢測(cè)的腳本,連拼寫錯(cuò)誤都要延期到運(yùn)行期才能被檢測(cè)出來。因此大量腳本的調(diào)試,還是相當(dāng)痛苦的。
            在這里,確保有有效的單元測(cè)試對(duì)腳本比對(duì)靜態(tài)語言要重要許多。這次做的工具,一開始并沒在意,但是到了中期以后,發(fā)現(xiàn)調(diào)試占用了大量的時(shí)間(因?yàn)锳rcGIS本身啟動(dòng)速度就比較慢,執(zhí)行一個(gè)調(diào)試周期很長),才開始給代碼部分地方補(bǔ)充了一些單元測(cè)試。有了單元測(cè)試以后,很大程度上縮短了調(diào)試周期。
            單元測(cè)試也是腳本重構(gòu)的必要條件。
            對(duì)于腳本而言,由于代碼量比傳統(tǒng)語言少很多,因此利用TDD一類測(cè)試先行的方法恐怕比在靜態(tài)語言上的收益要大得多。
            在腳本中,偶爾要寫一些防衛(wèi)代碼。在工程的早期,我在防衛(wèi)代碼,特別是類型約束的代碼上做了大量的工作。但是后來發(fā)現(xiàn),這些防衛(wèi)代碼本身引入的錯(cuò)誤不必原始工程來的少。因此中期之后,對(duì)于內(nèi)部的類,撤消了大部分的類型防衛(wèi)代碼,而改用測(cè)試保證內(nèi)部邏輯的一致性。這樣減輕了代碼量,提高了可讀性。

            --------------------------------

            其實(shí)腳本對(duì)于Web開發(fā)來說一點(diǎn)都不陌生。上次跟老李說這事,他說他至少寫了萬行的jsp和vbs代碼,調(diào)試不難,但是要保證正確性很難。測(cè)試很大程度上成為了腳本的救命稻草。
            一般來說,腳本比靜態(tài)語言省代碼,比靜態(tài)語言方便,比靜態(tài)語言XX,但是如果沒有測(cè)試,這些,都是鏡花水月而已。
            posted on 2008-05-16 15:51 空明流轉(zhuǎn) 閱讀(2111) 評(píng)論(4)  編輯 收藏 引用

            評(píng)論

            # re: 腳本編程瑣話 2008-05-16 16:37 陳梓瀚(vczh)
            “本來像C#那樣為每個(gè)屬性提供獨(dú)立的get/set其實(shí)挺好的。Python則把所有的成員的get/set都攏到一起了。”

            實(shí)際上我前幾天在對(duì)自己的腳本引擎進(jìn)行更新的時(shí)候,也是重新發(fā)明了這種方法。我以前并沒有過多的研究python和perl之類的語言,不過發(fā)現(xiàn)我的做法跟他們的做法在很多地方都自發(fā)的走到了一起。

            為什么要并在一起呢?實(shí)際上,并在一起有分散所不能比擬的好處。而且你要分散也可以,自己實(shí)現(xiàn)一個(gè)基類,提供一個(gè)綁定函數(shù)就可以了。腳本就是這樣,自己動(dòng)手,豐衣足食。畢竟是運(yùn)行時(shí)綁定的。  回復(fù)  更多評(píng)論
              

            # re: 腳本編程瑣話 2008-05-16 16:46 空明流轉(zhuǎn)
            @陳梓瀚(vczh)
            好處你詳細(xì)的說說,我倒是沒感覺有什么好不好處的,當(dāng)然也沒覺得有什么壞處。我只是討論一下這個(gè)問題我的處理方法而已。  回復(fù)  更多評(píng)論
              

            # re: 腳本編程瑣話 2008-05-16 17:46 Kevin Lynx
            = = 都忘了你以前是怎樣的,貌似現(xiàn)在還可以  回復(fù)  更多評(píng)論
              

            # re: 腳本編程瑣話 2008-05-16 20:21 空明流轉(zhuǎn)
            @Kevin Lynx
            啥還可以。。。以前咱倆也就是偶爾聊天而已,接觸不多。話說現(xiàn)在你已經(jīng)走上正職了吧。  回復(fù)  更多評(píng)論
              


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            久久国产高清一区二区三区| 欧美日韩精品久久久久| 久久99国产亚洲高清观看首页| 久久久久久久久无码精品亚洲日韩| 久久91精品久久91综合| 亚州日韩精品专区久久久| 久久久久亚洲AV无码永不| 国产精品成人99久久久久| 久久亚洲精品成人无码网站| 99久久精品国产麻豆| 欧美亚洲另类久久综合婷婷| 欧美va久久久噜噜噜久久| 久久www免费人成精品香蕉| 日本人妻丰满熟妇久久久久久| 国产91久久综合| 久久精品国产99久久久| 一级女性全黄久久生活片免费| 97超级碰碰碰久久久久| 久久精品久久久久观看99水蜜桃| 中文字幕久久欲求不满| 久久亚洲中文字幕精品有坂深雪| 久久久久无码中| 青青草国产精品久久| 亚洲AV无码久久精品色欲| 久久久久无码中| 久久se这里只有精品| 国产亚州精品女人久久久久久| avtt天堂网久久精品| 久久精品亚洲一区二区三区浴池 | 亚洲AV无码久久精品成人| 久久影院午夜理论片无码 | 久久亚洲AV成人无码| 免费一级欧美大片久久网| 久久99亚洲综合精品首页| 99久久精品这里只有精品| 亚洲国产精品人久久| 久久香蕉一级毛片| 91亚洲国产成人久久精品网址 | 久久性精品| 午夜福利91久久福利| 中文字幕无码久久精品青草|