ArcGIS Python編程案例(1)-Python語言基礎

前言 ||| 第二章 使用ArcPy編寫腳本


Python支持大部分在其他語言中出現的編程結構。在本章內容中,我們將會涉及到許多Python支持的編程結構。我們將會首先介紹如何創建一個新的Python腳本以及如何修改已有腳本。之后我們將深入了解Python的語言特性,比如添加注釋,創建變量,變量賦值以及Python的自動代碼補齊功能等,了解這些內容將讓你在使用Python編程的時候更為簡便。
接下來我們會介紹Python內置的數據類型,包括字符型,數值型,列表和字典等。類和對象是面向對象編程和Python語言中兩個基本的概念。你在ArcGIS中編寫地理處理腳本時會經常使用到上述這些復雜的數據結構。
另外,我們還將介紹條件語句和循環語句以及with語句,這些語句在涉及到ArcPy數據訪問模塊(Data Acccess module)中新的游標(cursor)對象時會經常使用。最后你還會了解到如何訪問模塊,這些模塊可以為Python提供更多附加功能。

該部分包含以下內容:

  • 如何創建并編輯Python腳本
  • Python語言特性
  • 注釋和變量
  • Python內置數據類型(字符,數字,列表和字典)
  • 復雜的數據結構
  • 循環語句
  • Python其他功能

IDLE

我在前言中提到過,ArcGIS桌面軟件安裝后,Python以及用于編寫代碼的IDLE工具也會一同安裝。IDLE是集成開發環境的縮寫(Integrated DeveLopment Environment)。由于IDLE在每一個ArcGIS桌面軟件安裝環境中都可以使用,我們使用IDLE開發環境來編寫本書中的大部分代碼,才外還會使用ArcGIS軟件中內置的Python窗口。你作為程序員還可能會更鐘意其他的開發工具,你也可以使用這些工具來編寫代碼。

Python shell窗口

點擊開始 | 所有程序 | ArcGIS | Python2.7 | IDLE打開Python的IDLE開發環境。注意Python版本會因為安裝的ArcGIS軟件版本不同而不同。比如,ArcGIS10.0版本安裝的是Python2.6,而ArcGIS 10.1版本安裝的則是Python2.7。
Python的shell窗口類似于下面的截圖:

Python的shell窗口用于顯示腳本生成的結果消息和錯誤消息。對于初學者來講,通常會誤認為地處理腳本代碼是在shell窗口中編寫。事實上并非如此。你需要打開另一個單獨的代碼窗口來保存你的腳本。
盡管shell窗口不能用來編寫完整腳本代碼,但可以以交互方式來即時獲取代碼反饋信息。ArcGIS軟件中包含一個內置Python shell窗口也是使用相同的方式。我們將在下個章節來介紹ArcGIS Python 窗口。

Python 腳本窗口

在IDLE中,腳本代碼編寫是在一個稱作Python 腳本窗口(Python script window)的獨立窗體中完成。點擊IDLE shell窗口中的File | New Window來打開一個新的代碼窗口。Python腳本窗口如下圖所示:

在這個新打開的腳本窗口中你就可以編寫代碼了。每個腳本需要保存到本地磁盤或者網絡驅動器中。腳本文件默認的文件擴展名為.py。

編輯已有Python腳本

右鍵單擊已有的Python腳本文件選擇Edit with IDLE,會彈出一個新的shell窗口以及載入腳本代碼內容的Python腳本編輯器。如下面的截圖:

在這個示例中,我們已經在IDLE中載入了ListFeatureClasses.py腳本文件。代碼內容出現在腳本窗口中:

現在腳本窗口已經打開,你就可以開始編寫或修改代碼了。你還可以在IDLE中執行一些簡單的代碼調試工作。代碼調試是指發現并修改代碼中錯誤的過程。

IDLE中運行腳本

在IDLE代碼窗口中編寫完地理處理腳本或者打開了一個腳本文件之后,你就可以在IDLE中執行代碼。運行腳本之前,你可以先在IDLE中進行代碼的語法檢查。在代碼窗口中,點擊Run | Check Module來執行語法檢查。
所有的語法錯誤都會顯示在shell窗口中。如果沒有發現任何語法錯誤的話,你將只會看到彈出的shell窗口。雖然IDLE可以用來檢查語法錯誤,但是并沒有提供邏輯錯誤檢查工具以及像PythonWin或者Wingware的開發環境提供的高級調試功能。
確認代碼中沒有語法錯誤后,你就可以運行腳本啦。點擊Run | Run Module在運行腳本:

所有的錯誤消息以及print語句和系統消息結果都會顯示在shell窗口中。print語句可以將字符串輸出到shell窗口中。該語句通常用于更新一個正在運行腳本的狀態或者代碼調試。

Python語言基礎

為了能夠更好地編寫ArcGIS地理處理腳本,你需要先了解一些基本的Python語言結構。盡管相對其他大部分編程語言,Python更容易學習,但是仍需要花費一定時間來學習并熟練使用。該部分內容將向你介紹如何創建變量,如何給變量賦不同數據類型的值,如何理解賦值給變量的不同數據類型,如何使用不同類型的語句,如何使用對象,如何讀寫文件以及如何導入第三方的Python模塊。

注釋

Python腳本需要遵循一個通用的結構。每個腳本的開頭部分應作為說明文檔,用以詳細描述腳本名稱,作者以及腳本功能的總體描述。說明文檔部分在Python中可以通過注釋功能來完成。注釋指用來添加到腳本中作為腳本功能說明性文檔的代碼語句。這些代碼以#或者##開始,后面跟著你需要說明解釋的文本內容。Python解釋器不會處理這類代碼。它們只是解釋說明代碼意義。如下圖所示,注釋行代碼用紅色字體顯示。你也應該嘗試在腳本中添加注釋來描述腳本中的重要部分。無論對你或對其他程序員這對今后修改代碼都是非常有用的。

導入模塊

盡管Python包含了大量的內置功能,你還是會經常需要訪問一些專門的功能包, 功能包又包含在一些外部模塊中。舉個例子,Math模塊包含了與數值處理有關的功能,R模塊則提供了數據統計分析的功能。使用import語句導入模塊。編寫ArcGIS地處理腳本時,通常就需要導入ArcPy模塊,該模塊是用于訪問ArcGIS中提供的GIS工具和函數的Python包。import語句會是腳本中的第一行代碼(不包括注釋部分):

import arcpy,os
變量

從高層面來說,變量可以看做是腳本運行過程中用來存儲值的計算機內存區域。在Python中,通過給定名稱和值來定義變量。變量賦值之后只要簡單地引用變量名稱,就可以在腳本中的不同位置來獲取該變量值。比如,你創建了一個包含要素類名稱的變量,該變量之后被Buffer工具調用生成了一個新的要素集。只要簡單地給定一個名稱,然后緊跟著賦值運算符(=)和要賦的值就可以創建一個變量:

fcParcels = "Parcels"
fcStreets = "Streets"

下表說明了變量名和通過上面的示例代碼賦值給變量名的變量值的關系:

變量名 變量值
fcParcels Parcels
fcStreets Streets

你在創建變量時候必須遵守一些命名規則,主要包含以下內容:

  • 使用字母,數字和下劃線
  • 首字母必須為字母
  • 除了下劃線不能包含其他特殊字符
  • 不能使用Python關鍵字

大概有幾十個Python關鍵字是必須要避免使用的,包括class,if,for,while等等。
下面是一些合法的變量名稱的例子:

  • featureClassParcel
  • fieldPopulation
  • field2
  • ssn
  • my_name
    下面是一些非法的變量名稱的例子:
  • class (使用了Python關鍵字)
  • return (使用了Python關鍵字)
  • $featureClass (包含特殊字符,必須以字母開頭)
  • 2fields (必須以字母開頭)
  • parcels&Streets (包含特殊字符)

Python語言是區分大小寫的,因此需要特別注意腳本中變量命名和大小寫。對于Python新人來說,大小寫問題很可能是最為常見的錯誤原因,因此遇到代碼錯誤時需要考慮到這種情況。我們看一個例子。下面的三個變量的變量名稱除了大小寫不同之外是一樣的,但Python仍然認為是三個不同的變量。

mapsize = "22x34"
MapSize = "8x11"
Mapsize = "36x48"

如果打印這三個變量:

print mapsize
print MapSize
print Mapsize

運行結果如下:

22x34
8x11
36x48

Python中變量名稱需要在整個腳本中保持一致。推薦是采用駝峰式命名,即變量名稱的首個單詞全部采用小寫,后續的每個單詞的首字母大寫。下面以fieldOwnerName的變量名舉例說明。首個單詞(field)全部是小寫,后面跟的第二個單詞(``Owner)和第三個單詞(Name`)都是采用首字母大寫的形式。
Python中變量類型是動態的。動態類型(Dynamic typing)意味著你可以只定義變量名稱和并賦值給它,而不需要定義變量的數據類型。常用的數據類型包括:

數據類型 示例
字符型 "Streets" fcName="Streets"
數值型 3.14 percChange=3.14
布爾型 True ftrChanged=true
列表 Streets,Parcels,Streams lstFC=["Streets","Parcels","Streams"]
字典 '0':Streets,'1':Parcels dictFC={'0':Streets,'1':Parcels }
對象 Extent spatialExt=map.extent

我們將在后面的內容中詳細介紹數據類型。
C#中你需要先定義變量的名稱和類型才能使用。在Python中只要給定變量名稱和值之后就可以使用。Python會在后臺確定變量所包含的數據類型。
舉個例子,在下面的代碼示例中,我們創建了一個aTouchdown的變量,該變量被定義為整型,也就意味著變量只能接受整型數據。我們給這個變量賦值為6:

int aTouchdown;
aTouchdown = 6;

在Python中同一變量可以動態賦值。Python解釋器會動態地處理賦給變量的數據類型:

aTouchdown = 6

你編寫的ArcGIS Python地理處理腳本中需要經常引用本地計算機或者共享服務器上的數據集的位置。變量中的數據集地址通常由路徑組成。Python中路徑名稱是一類特殊情況需要特別說明。反斜線(\)是Python中保留的轉義字符和行連接符,因此在定義路徑變量時需要使用兩個反斜線(\)或者一個斜線(/)或是在使用單個反斜線時需增加字母r前綴。下面舉例說明這一問題。
不正確的路徑引用:

fcParcels = "c:\Data\Parcels.shp"

正確的路徑引用:

fcParcels = "c:/Data/Parcels.shp"
fcParcels = "c:\\Data\\Parcels.shp"
fcParcels = r"c:\Data\Parcels.shp"

有時候你知道腳本中需要一個變量,但是又沒有必要事先了解要賦給變量的是什么數據。在這種情況下,你就可以先簡單地定義一個變量而不賦值給它。腳本運行中賦給變量的值也可以更改。
變量可以保存許多不同的數據類型,既包括像字符型和數值型這樣的基本數據類型(primitive datatype),也可以包括像列表,字典甚至對象這樣復雜的數據類型。接下來我們將介紹可以賦值給變量的不同的數據類型以及Python提供的數據操作方法。

內置數據類型

Python包含許多內置的數據類型。我們首先介紹的是字符型(string)。我們已經見過一些字符型變量的例子,不過這些變量還可以執行許多操作方法,讓我們進一步了解這一數據類型。
字符串
字符串是用于存儲和表示文本信息的有序字符集合。簡單地講就是字符串變量保存文本內容。字符串括在單引號或雙引號內賦值給變量。字符串可以是名稱,要素類名稱,where條件語句以及其他可以用文本表示的情況。
字符操作
Python中提供了很多字符串的操作方法。字符串連接就是最為常用的功能之一,并且容易實現。使用+運算符就可以將運算符兩邊的字符串合并為一個新的字符串變量:

shpStreets = "c:\\GISData\\Streets" + ".shp"
print shpStreets

運行結果如下:

c:\GISData\Streets.shp

你可以使用Python提供的==(兩個連續的=)運算符來測試字符串是否相等。不要混淆了相等運算符和賦值運算符,后者使用單個等號符號。相等運算符是用于判斷兩個變量是否相等,而賦值運算符則是賦值給變量:

firstName = "Eric"
lastName = "Pimpler"
firstName == lastName

運行結果如下:

False

你還可以使用in運算符來判斷字符串的包含關系,如果第一個算子包含在第二個算子中的話將返回True。

fcName = "Floodplain.shp"
print ".shp" in fcName
print ".shx" in fcName

運行結果如下:

True
False

我之前簡單提到過字符串是有序的字符集合。這意味著什么?這將意味著我們可以獲取字符串中的單個字符或者子字符串。在Python中,獲取單個字符的操作稱作索引(indexing),而獲取連續字符的時候操作切片(slicing)
字符串中的字符可以通過括在方括號內的數字索引值來獲取。比如你可以使用fc[0]來獲得獲取fc變量中字符串的第一個字符。負的位置數值用于從字符串末端開始反向向前查找。在這種情況下,字符串最后一個字符的索引號為-1。使用索引會創建一個新的變量來保存返回的字符:

fc = "Floodplain.shp"
print fc[0]
print fc[10]
print fc[13]

運行結果如下:

'F'
'.'
'p'

下圖說明了字符串作為字符的有序集合的組織形式,第一個字符占據位置0,第二個字符占據位置1,后續的字符依次占據下一個索引位置:


字符串索引可以獲取字符串變量中的單個字符,而字符串切片則可以讓你獲取一個連續序列的子字符串。切片的格式和用法同索引類似,不過需要增加第二個索引值用來告訴Python要返回多少字符。
下面是一個切片的例子。Floodplain.shp變量值已經賦值給theSring變量。使用theSring[0:5]語句就可以獲取一個包含Flood的變量:

theString = "Floodplain.shp"
print theString[0:5]

運行結果如下:

Flood

Python切片返回的字符是以第一個位置開始到第二個位置結束,但不包括第二個位置的字符。這點對于Python新手會感到困惑,而且也是常見的錯誤原因。我們上面的示例中返回的變量包含Flood內容。第一個字符是F占據位置0。最后一個字符d占據位置4。需要注意索引數5位置上的字符并沒有返回,這是因為Python切片僅返回到第二個位置但不包含第二個位置的字符

兩個位置值都可以忽略。這種情況下相當于通配符的作用效果。theString[1:]的情況下會告訴Python要返回從第二個字符開始的所有字符。theString[:-1]的情況則告訴Python要返回除最后一個字符外的所有字符。
Python是處理文本的優秀語言,它提供了許多處理字符的功能。其中大部分的功能已經超出了本書介紹的范圍,下面列出的功能都可以實現:

  • 字符串長度
  • 大小寫轉換
  • 去除首尾空格
  • 查找字符
  • 替換文本
  • 基于分隔符拆分字符串
  • 文本格式化

數值
Python同樣也內置支持(built-in support)包括整型,長整型,浮點型和復數等數值數據。數值賦值給變量的方式跟字符基本一致,只是不需要將值括在引號內,而且該值必須是一個數值型數據。
Python支持所有常用的數值計算,包括加,減,乘,除以及取模(求余)等。另外Python還支持絕對值,字符型轉為數值型和四舍五入等功能。
盡管Python也提供了一些內置的數學函數,但使用math模塊可以獲取更多更高級的數學函數。使用這些函數,你首先需要按照下面的方式導入math模塊:

import math

math模塊提供的函數包括上下取整函數,絕對值函數,三角函數,對數函數,弧度轉換以及雙曲線函數等。
列表
我們介紹的第三個Python內置數據類型是列表。列表是對象的有序集合,這些數據可以是Python支持的數據類型的任意一種或幾種,比如數值,字符串,其他列表,字典或對象等。舉個例子來講就是一個列表對象可以同時存放數值和字符數據。列表是從零開始索引(zero-based),也就是說列表中的第一個元素占據位置0,后面的元素位置索引依次遞增1。另外,列表是可動態伸縮的。
使用方括號([ ])將一系列值括起來賦值給變量即可創建列表。變量名稱后面緊跟方括號括起來的一個整數值的語句格式就能夠獲取列表中的一個元素值。下面的示例代碼用來說明這一過程。你還可以使用切片來返回多個元素值。使用列表切片將返回一個新的列表對象。

fcList = ["Hydrants", "Water Mains", "Valves", "Wells"]
fc = fcList[0]
print fc
fc = fcList[3]
print fc

運行結果如下:

Hydrants
Wells

列表是動態可變的,可以對列表內容進行增加,刪除和更改。完成這些操作也不需要創建一個新的備份列表對象。更改列表中元素值可以通過切片或索引操作來完成。索引操作更改一個元素值,而切片操作則可以更改多個列表元素值。
列表支持許多對列表中的元素值進行操作的方法。你可以使用sort()
方法來對列表內容按照升序或降序排列。你可以使用append()方法在列表末尾添加元素對象,使用insert()方法在列表中指定位置插入元素對象。你可以使用remove()方法來刪除首次出現在列表中的元素值,使用pop()方法則刪除最后添加到列表中的元素并返回該元素值。你還可以使用reverse()方式實現列表內容的前后順序倒置。
元組
元組與列表類似,但是有一些重要的區別。與列表一樣元組也是一個值的序列。兩者的區別就是元組是不可變的,而且使用圓括號來創建而不是方括號。創建一個元組就是簡單地把一些用逗號分隔符隔開的值括在圓括號內,如下面的示例代碼所示:

fcTuples = ("Hydrants","Water Mains","Valves","Wells")

同列表一樣,元組也是從0開始索引。獲取元組中的元素值的方法同列表一樣。下面的示例代碼就說明了這個問題:

fcTuples = ("Hydrants","Water Mains","Valves","Wells")
print fcTuples[1]

運行結果如下:

Water Mains

當需要要求數據保持靜態的時候,通常使用元組來代替列表。這是因為使用列表就不能保證這一點,而使用元組就可以。
字典
字典是我們介紹的第二類Python集合對象。字典跟列表類似,不過字典是對象的無序集合。不同于使用位置索引值來從集合中獲取對象,字典是使用鍵值(key)來獲取字典內的元素值。字典中的每一個鍵值都有一個與之對應的數據值。與列表類似,字典可以使用dictionary類中的方法實現字典內容的增減操作。在下面的示例代碼中,你將會了解到如何創建字典并向字典中填充數據以及如何通過鍵值來獲取值。字典是使用花括號({ })來創建的。在括號內每一個鍵值是用引號括起來后面緊跟一個冒號以及對應的數據值。字典內的鍵值對用逗號隔開:

##創建字典
dictLayers = {'Roads': 0, 'Airports': 1, 'Rail': 2}
##使用鍵值獲取值
print dictLayers['Airports']
print dictLayers['Rail']

運行結果如下:

1
2

基本的字典操作包括獲取字典內的元素個數,使用鍵值獲取數據值,判斷某個鍵值是否存在,將鍵值轉為列表對象以及獲取數據值列表。字典內容可以更改,增加以及刪除。這也就意味著Python無需創建一個新的dictionary對象來保存字典的更改版本數據。給字典的鍵值賦值的操作可以通過將要賦值的鍵值擴到方括號內,然后讓其等于某個值就可。

跟列表不同,由于字典內容是無序的所以不能使用切片操作。使用keys()方法返回字典中所有鍵值的一個集合來遍歷字典中的所有值或者也可以用來單獨獲取或者設置數據值

類和對象
類和對象是面向對象的編程中最為基本的概念。盡管Python更傾向于是一種過程語言,但是它同樣支持面向對象編程。在面向對象編程中,類是用于創建對象實例的。你可以認為類是用于創建一個或多個對象的圖紙。對象實例有相同的屬性和方法,然而每個對象所包含的數據可以而且通常是不同的。對象在Python中是由屬性和方法組成的復雜的數據類型,跟其他數據類型一樣可以賦值給變量。屬性包含了與對象有關的數據,而方法則是對象可以執行的動作。
下面的示例中很好地闡釋說明了上述概念。在ArcPy中,Extent類是由左下角坐標和右上角坐標指定的一個矩形范圍。Extent類包含了許多屬性和方法。其中屬性包括XMin,XMax,YMin,YMax,spatialReference等等。橫縱坐標的最大和最小坐標值(XMin,XMax,YMin,YMax)指定了矩形范圍大小。spatialReference屬性保存了Extent類中的SpaitalReference對象的參考坐標系數據。Extent類的對象實例可以使用點標注符(dot notation)來設置并獲取以上這些屬性值。示例代碼如下所示:

import arcpy
##路徑替換為本地計算機上的文件路徑
fc = "c:/ArcpyBook/data/TravisCounty/TravisCounty.shp"
## 使用游標對象獲取每一個要素的范圍和空間參考(游標的概念在后面會詳細介紹)
for row in arcpy.da.SearchCursor(fc, ["SHAPE@"]):
    # 獲取TravisCounty數據的范圍
    ext = row[0].extent
    # 打印四至坐標和參考坐標系
    print "XMin: " + str(ext.XMin)
    print "XMax: " + str(ext.XMax)
    print "YMin: " + str(ext.YMin)
    print "YMax: " + str(ext.YMax)
    print "Spatial Reference: " + ext.spatialReference.name

運行結果如下:

XMin: 2977896.74002
XMax: 3230651.20622
YMin: 9981999.27708
YMax: 10200100.7854
Spatial Reference: NAD_1983_StatePlane_Texas_Central_FIPS_4203_Feet

Extent類有許多方法,其中大部分是驗證Extent對象與其他幾何對象的幾何關系的方法。比如有contains(),crosses(),disjoint(),equals(),overlaps(),touches()以及within()
你需要了解的另一個面向對象編程的概念是點標注符。點標注符(dot notation)提供了一種獲取對象屬性和方法的方式。點標注符用來指明某個屬性或方法隸屬于某個特定的類。
使用點標注符的語句是對象實例后面緊跟一個點符號(.)以及屬性或是方法名稱。獲取對象屬性和方法的語句都是一樣。如果點符號后面的語句末尾是圓括號括起來的零個或多個參數的話,那就說明正在訪問對象的一個方法。下面的兩個例子能夠很好地說明這個問題:

屬性(Property) => extent.XMin
方法(Method) => extent.touches()

語句
你使用Python編寫的每一行代碼都稱作語句。Python中有許多類型的語句,包括變量命名和賦值語句,基于驗證結果執行代碼的條件語句,用來執行多次相同語句塊的循環語句等等。你在編寫腳本語句時需要遵循許多規則。你已經遇到過一種類型的語句:變量命名和賦值語句。
條件語句
if/elif/else語句是Python中重要的條件語句,該語句用于判斷true/false狀態。使用條件語句能夠控制程序的流程。這里舉幾個例子說明:如果變量是一個點要素類,那么就獲取其X,Y坐標值;如果要素類的名稱為Roads,那么就獲取其Name字段。
if/elif/else這樣的條件語句用來判斷true/false狀態。在Python中,"true"值是指任何非零數字或非空對象。"false"值是指零值或空對象,即非true值。比較測試返回1或者0(true或者false),布爾與或(and/or)操作符返回true或者false。

if fcName == 'Roads':
    gp.Buffer_analysis(fc, "c:\\temp\\roads.shp", 100)
elif fcName == 'Rail':
    gp.Buffer_analysis(fc, "c:\\temp\\rail.shp", 50)
else:
    print "Can't buffer this layer"

Python代碼必須遵循一定的語法規則。代碼遇到分支語句之前,逐句依次執行。分支語句通常在if/elif/else中實現。另外,使用for或者while循環語句也能更改語句的執行順序。Python能夠自動識別語句和代碼塊的范圍,因此不需要在語句塊前后增加括號或者分隔符。實際上,Python使用縮進來組合語句塊。許多程序語言使用分號作為語句的結尾,而Python使用行結束符來標識語句結尾。復合語句(compound statement)會包含“:”符號。復合語句遵循以下模式:頭語句(header)以冒號結束,頭語句內的編寫的語句塊使用縮進。
縮進對Python解釋語句的方式非常重要,這里需要特別說明一下。前面內容提過,Python使用縮進來檢測一個連續的語句部分。默認情況下,所有的Python語句中遇到循環語句,條件語句,try/except語句和with語句前都應該左對齊。這里包括forwhile循環語句,if/else語句,try/except語句和with語句。同一語句塊內的所有語句在語句塊結束之前使用相同的縮進。
循環語句
循環語句可以讓程序根據需要來重復執行某段代碼內容。while循環語句中,只要循環體開始部分的條件判斷為真就會重復執行語句塊。當條件判斷為假,Python則開始執行while循環體后面的代碼。在下面的示例代碼中,將10賦值給變量x。while循環語句判斷x是否小于100,如果x小于100則將當前x的值輸出到屏幕同時將x的值增加10。語句執行后再進行while語句的條件判斷,第二次判斷時當前x的值為20,因此條件判斷結果仍為真。該過程直到x大于100時結束。在那個時候,條件判斷結果為假,循環語句執行結束。這一點對于中止跳出while循環語句是非常重要的。否則的話,你將會先入死循環中。死循環就是計算機程序中的無限循環一段指令,死循環的出現要么是由于循環語句中無中止條件,或是有中止條件但從未滿足該條件,亦或是中止條件滿足后導致循環重新開始:

x = 10
while x < 100:
    print x
    x = x + 10

for循環語句會按照預先設定的循環次數來執行一段語句塊。for循環有兩種情況,一種是計數循環(counted loop),根據設定的循環次數來循環運行一段語句塊,另一種是列表循環(list loop),允許你迭代列表中的所有對象。下面的示例代碼中,列表循環中會對字典中的每一個值執行一次代碼,然后循環結束:

dictLayers = {"Roads":"Line","Rail":"Line","Parks":"Polygon"}
lstLayers = dictLayers.keys()
for x in lstLayers:
    print dictLayers[x]

有些時候中止循環是很有必要的。breakcontinue語句可用來中止循環。break語句跳出離它最近的循環體,而continue語句則是跳回到離它最近的循環體的最高層繼續下一個循環。兩個語句可以出現在語句塊中任何地方。
try語句
try語句是用來處理異常的完整的復合語句。異常是一種主要用來捕獲錯誤或觸發錯誤的高級控制機制。Python中的異常可以捕獲或者觸發。當代碼中的發生錯誤時,Python會自動觸發異常,這些異常可以在代碼中處理或者忽略掉。你作為程序員來決定是否捕獲自動觸發的異常。異常還可以手動觸發。在這一案例中,你將會了解到捕獲人工觸發異常的常規處理流程。
Python中的try語句有兩種基本類型:try/except/elsetry/finally。一個基本的try語句從try語句頭開始,后面緊跟著語句塊,之后為一個或多個可選的except語句,這些except語句用來命名捕獲的異常,最后是一個可選的else語句:

import arcpy
import sys
inFeatureClass = arcpy.GetParameterAsText(0)
outFeatureClass = arcpy.GetParameterAsText(1)
try:
    #如果輸入的要素類名稱已經存在,觸發一個錯誤
    if arcpy.Exists(inFeatureClass):
        raise overwirttenError(outFeatureClass)
    else:
        #其他處理步驟
except overwrittenError as e:
    #返回消息代碼12,同時還提供輸出要素類名稱增加到消息中
    arcpy.AddIDMessage("Error",12,str(e))

try/except/else語句工作流程如下所述。try語句開始后,Python會標注說明現在已經位于try語句塊中,同時也就知道當出現任何異常情況時Python會將異常提交給except語句來處理。如果找到了匹配異常的except語句,Python就會執行該except語句中代碼。異常處理完成后就會開始執行整個try語句塊后面的代碼。在這種情況下else語句則不會執行,而try語句塊內的語句都會執行。如果沒有異常發生,指針將會先跳到else語句執行完else中的代碼之后再調到整個try語句塊后面的首行代碼。
另一種類型的try語句是try/finally語句,該類型語句會執行終止操作(比如關閉文件,釋放等)。try語句中使用finally語句,無論異常情況是否發生都將會執行finally語句塊中的代碼。
try/finally語句工作流程如下所述。異常發生時,Python會先執行try語句塊,之后再執行finally語句塊,隨后繼續執行整個try語句塊后面的代碼。如果沒有異常發生,Python則執行完try語句塊后接著執行finally語句塊。你希望無論異常是否發生都要保證某項操作執行的時候,使用try/finally語句就非常有幫助。比如像關閉文件或者是斷開數據庫鏈接這樣的釋放清理(cleanup)操作通常都會放到finally語句塊中,以保證無論異常是否出現釋放清理操作都會執行:

import arcpy
from arcpy import env
class LicenseError(Exception):
    pass
env.workspace="E:/dem.gdb"      
try:
    if arcpy.CheckExtension("3D") == "Available":
        arcpy.CheckOutExtension("3D")
    else:
        raise LicenseError
    arcpy.HillShade_3d("N53E126","dem_hill",300)
    arcpy.Aspect_3d("N53E126","dem_aspect")

except LicenseError:
    print "3D Analyst license is unavailable"
except:
    print arcpy.GetMessages(2)
finally:
    arcpy.CheckInExtension("3D")

with語句
當需要執行成對出現的兩個關聯操作以及兩個操作中間的一段代碼的時候,使用with語句就很方便。使用with語句常見的情況是文件的打開,讀取和關閉。文件打開和關閉是關聯操作,而讀取文件以及處理文件內容則是兩個關聯操作中間的一段代碼。使用10.1版本新引入的cursor對象來編寫ArcGIS地理處理腳本情況就很適合使用with語句。我們將會在后面的章節中討論cursor對象的更多細節,這里我就先簡單介紹一下。游標對象是內存中要素類或表的屬性表數據的備份。ArcGIS中提供了許多類型的游標。插入游標用來插入新的記錄,搜索游標是只讀的記錄備份,更新游標可以用來編輯或刪除記錄。使用with語句來打開游標,執行某些操作后會自動釋放游標。
使用with語句來自動關閉文件或者游標對象,帶來更為簡潔高效的編碼體驗。with語句跟try/finally語句很像,但是代碼更少。在下面的示例代碼中,使用with語句來創建一個搜索游標,讀取游標對象中的信息之后隱式地關閉游標:

import arcpy
fc = "c:/data/city.gdb/streets"
#打印每行數據的ID值并獲取幾何屬性
with arcpy.da.SearchCursor(fc,("OID@","SHAPE@AREA")) as cursor:
    for row in cursor:
        print ("Feature {0} has an area of {1}".format(row[0],row[1]))
文件讀寫(File I/O)

你會經常需要讀寫計算機中的文件。Python包含了一個內置的對象類型提供了獲取文件的方式。盡管我們只介紹Python文件操作功能的一小部分,但這些功能都是最為常用的功能,包括文件的打開和關閉,文件的讀取和寫入等。
Python的open()函數會創建一個文件對象,該對象相當于你的電腦中文件的一個鏈接。你在對文件進行讀寫數據之前必須先對該文件調用open函數。open()函數中的第一個參數是你要打開文件的路徑,第二個參數對應某個模式,通常是讀(r),寫(w)或者添加(a)。r值表示你打開文件只是進行讀取操作,而w值表示你打開文件需要進行寫入操作。打開一個已有文件進行寫操作時,Python會覆蓋掉文件中已有數據,因此選擇寫入模式的時候需要注意。添加模式(a)將會打開文件進行寫入操作,但不會覆蓋掉任何已有數據,只是將新寫入的數據添加到文件的末尾。下面的示例代碼會說明使用open函數在只讀模式下打開文件的用法:

f = open('Wildfires.txt','r')

在完成文件的讀寫操作后,你需要使用close方法來關閉文件。
文件打開之后,你可以通過不同方式和方法來讀取數據。最典型的就是通過
readline()方法來一次讀取一行數據。readline()方法可以用來一次讀取文件的一行數據并賦值給一個字符型變量。你就需要在Python代碼中使用循環模式來逐行讀取整個文件。如果你想一次讀取整個文件并放到一個變量中的話,你就可以使用read()方法,該方法會讀取整個文件直至文件結束標志(EOF)。你還可以使用readlines()方法來讀取整個文件,并在遇到文件結束符前按行分成各個單獨的字符串。
下面的示例代碼中,我們以只讀模式打開一個Wildfires.txt的文件,并調用readlines()方法將文件的整個內容讀取到lstFires變量中去lstFires變量是一個Python列表,文件的每行內容都是該列表中的一個字符串元素值。在本案例中,Wildfires.txt是一個逗號分隔符的文本文件,該文件中包含了每次火情的經緯度位置以及可信度數據。我們將迭代讀取lstFires中的每行文本,調用split()函數按照逗號分隔符來分別提取緯度,經度和可信度數據。經緯度值用于創建一個新Point對象,該對象將會使用插入游標插入到要素類中:

import arcpy,os
try:    
    #打開要讀取的文件
    f = open('Wildfires.txt','r')
    lstFires = f.readlines()
    cur = arcpy.InsertCursor("e:/dem.gdb/FireIncidents")
    for fire in lstFires:
        if 'Latitude' in fire:
            continue       
        vals = fire.split(",")        
        latitude = float(vals[0])
        longtitude = float(vals[1])
        confid = int(vals[2])
        print(longtitude,latitude)
        pnt = arcpy.Point(longtitude,latitude)
        feat = cur.newRow()
        feat.shape = pnt
        feat.setValue("CONFIDENCEVALUE",confid)
        cur.insertRow(feat)
    del feat
    del cur
except:
    print arcpy.GetMessages()
finally:    
    f.close()

正如讀取文件的情況一樣,你可以使用一些方法來把數據寫入文件中。write()方法大概是最方便的,該方法引用一個字符串參數然后把該參數值寫入到文件中。wirtelines()方法可用于將列表結構的內容寫入到文件中。在下面的示例代碼中,我們創建了一個fcList的列表,該列表中包含了一些要素類名稱。我們可以調用writelines()方法將列表內容寫入到文件中:

outfile = open('c:\\temp\\data.txt','w')
fcList = ["Strams","Roads","Counties"]
outfile.writelines(fcList)
outfile.close()

總結

我們介紹了一些基本的Python語言編程的概念,這些概念是你編寫地理處理腳本之前需要事先了解的。本章內容我們首先介紹了用于編寫和調試代碼的IDLE開發環境的情況。你了解到如何創建一個新的腳本,如何編輯一個現有的腳本文件以及如何檢查語法錯誤和執行腳本。我們還介紹了基本的編程語言結構,比如模塊導入,變量創建和賦值,if/else條件語句,循環語句以及不同的數據類型,其中包括字符,數值,布爾,列表,字典和對象,你還了解到如何讀寫文本文件。
在下一部分中,你還會了解到在ArcGIS中使用Python編寫地理處理腳本的基本技巧。你還會了解到如何使用ArcGIS桌面軟件中內置的Python窗口,如何在腳本中導入ArcPy包,如何在腳本中執行ArcToolbox工具,如何在腳本編寫中利用幫助系統,如何使用變量保存數據以及如何訪問各種ArcPy模塊。


前言 ||| 第二章 使用ArcPy編寫腳本

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,837評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,196評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,688評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,654評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,456評論 6 406
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,955評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,044評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,195評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,725評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,608評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,802評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,318評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,048評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,422評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,673評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,424評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,762評論 2 372

推薦閱讀更多精彩內容