Instant Python 中文縮減版


前言

本文主要來自《Python基礎教程(第2版)》([]Magnus Lie Hetland著,司維 曾軍崴 譚穎華譯 人民郵電出版社) 中的“附錄A 簡明版本”,對於其中的有問題之處進行修改,僅是個人理解,若有錯誤敬請見諒。



簡介


本部分是基於我([]Magnus Lie Hetland)的流行網絡教程“instant Python”http://hetland.org/writing/instant-python.html)的一個簡短的Python介紹。它面向那些已經掌握一到兩門語言,希望能夠快速掌握Python的程序員。有關下載和執行Python解釋器的信息,請參見第1章。


A.1 基礎知識


如果想對Python 語言有一個基本了解,那么可以把它想象成偽代碼——其實這已經非常接近事實了。變量沒有類型,所以不需要進行聲明。變量在賦值時出現,不再使用的時候則會消失。賦值使用=運算符完成,像下面這樣:

x = 42

注意:相等性的檢測是由==運算符完成的。

還可以一次對多個變量進行賦值:

x, y, z = 1, 2, 3
first, second = second, first
a = b =123 

語句塊 通過並且只通過 縮進 表示(沒有begin/end語句或者括號)。下面是一些普通的控制結構:

前兩個例子是等價的。

if x < 5 or (x > 10 and x < 20):
    print "The value is OK."

if x < 5 or 10 < x < 20:
    print "The value is OK."

for i in [1, 2, 3, 4, 5]:
    print "This is iteration number ", i
    x = 10

while x >= 0:
    print "x is still not negative."
    x = x-1

for 循環中的索引變量會迭代列表(本例中使用方括號寫成)中的元素或者其他可迭代對象。為了實現“普通的”for循環(也就是計數循環),可以使用內建的range函數:

# 打印0-99的值,包括0和99
for value in range(100):
    print value

以井號開頭的行是注釋,會被解釋器忽略。

 

現在(理論上)已經介紹了Python內實現算法的大部分內容。接下來增加一些基本的用戶交互。為了(從命令提示符)獲取用戶輸入,可以使用內建的input函數:

x = input("Please enter a number: ")
print "The square of that number is ", x*x 

input 函數會顯示(可選的)給定的提示符,並且讓用戶輸入任何合法的Python值。本例中,我們期望的是數字。如果輸入了其他的類型值(比如字符串),程序會以一個錯誤信息終止。為了避免出現這種情況,需要增加一些錯誤檢查機制。這里我先不介紹,我們先假設想讓程序將用戶的輸入以字符串形式 逐字地 返回,(這樣就可以輸入任何值),可以使用raw_input函數。如果想要將輸入字符串s轉換為整數,可以使用int(s)


 

注意:如果想要使用input輸入一個字符串,那么用戶需要顯式地寫出引號。在Python中,字符串可以用單、雙引號括起。在Python3.0中,原始的input方法被取消了,而raw_input被重命名為input,請參見附錄D 獲取Python3.0的更多信息。



剛剛介紹了控制結構、輸入和輸出——現在來看看“華麗的”數據結構。其中最重要的算是列表和字典。列表用 中括號 實現,可以(很自然地)進行嵌套:

name = ["Cleese", "John"]
x = [[1, 2, 3], [y, z], [[[]]]]

 

列表最棒的地方之一就是可以單獨訪問它的元素,也可以通過 索引 以及 分片 分組訪問。索引訪問(和很多其他語言一樣)是在列表后加上以中括號括起來的索引值實現的(注意,第一個元素的索引為0)。

print name[1], name[0] # Prints "John Cleese"
name[0] = "Smith"

 

分片基本上和索引一樣,不過可以表示結果的起始和結束索引,使用冒號(:)進行分隔;

x = ["SPAM", "SPAM", "SPAM", "SPAM", "SPAM", "eggs", "and", "SPAM"]
print x[5:7] # Prints the list ["eggs", "and"]

注意,結尾索引是不包含在結果內的。如果不寫明兩個索引中的一個,那么程序會假定需要那個方向的所有元素。換句話說,分片x[:3]意為“x中從開始到3號元素之間的所有元素,不包括3號元素”(也可以說表示第4個元素,因為是從0開始計數的)。分片x[3:]則表示“x中從3號元素(包括)開始到結尾之間的所有元素”。真正有意思的是,分片操作也可以使用負數:x[-3]表示倒數第3個元素。

 

那么,現在說說字典。簡單來說,它們類似於列表,但內容是無序的。那么怎么進行索引呢?每個元素都有一個,或稱名稱,它用類似於真正字典的方式查找元素。下面的例子演示了用於創建字典的語法:

phone = { "Alice": 23452532, "Boris" : 252336,
    "Clarice": 2352525, "Doris": 23624643 }

person = {'first name': "Robin", 'last name': "Hood",
    'occupation': "Scoundrel"}

 

現在要獲得person的職業(occupation)的話,可以使用表達式person["occupation"]。如果想要改變的 姓,可以像下面這樣做:

person['last name'] = "of Locksley"

很簡單吧?字典類似於列表,也可以包含其他字典。當然,字典也能包含列表。同樣地,列表也能包含字典。這樣一來,就可以輕松創建一些很高級的數據結構了。

 

A.2 函數

 

下一步就是抽象。這個過程類似於給一段代碼起個名字,並且利用一些參數調用它。換句話說,就是定義一個函數,也叫做過程(procedure)。很簡單,像下面這樣,使用關鍵字def

def square(x):
    return x*x

print square(2) # 打印4

 return語句用來從函數返回值。

 

在一個函數傳遞參數時,同時也就將參數綁定到了值上,也就創建了新的引用。這就意味着可以在函數內部直接修改原始值。但是如果將參數名引用到其他值上面(重綁定),那么這個修改就不會影響到原來的變量。這種工作方式類似於Java。讓我們看下面的這個例子:

def change(x):
    x[1] = 4

y = [1, 2, 3]
change(y)
print y # Prints out [1, 4, 3]

 

你看到了,傳入的是原始列表,如果函數對其進行了修改,那么這些修改也會傳遞到調用函數的地方。不過請注意下面例子的行為,函數體 重綁定 了參數:

def nochange(x):
    x = 0

y = 1
nochange(y)
print y # 打印1

 

為什么y沒變?因為函數沒有改變這個值!傳入的值是1——不能用更改列表的方式更改一個數字。數字1就是(也永遠是)數字1.我所做的是改變參數x的值的引用,這樣不會影響到調用。

Python 有各種各樣的參數,例如命名的參數(named argument)和默認值參數(default argument),它們可以處理一個函數的多個參數。請參見第6章獲取這部分更多信息。

如果知道如何使用函數,那么剛才所講到的基本上就是在Python內需要知道的。

不過了解“Python的函數是值”這個概念可能會比較有用。如果有一個square的函數,那么可以像下面這樣做:

queeble = square
print queeble(2) # 打印 4

為了能不用參數調用函數,必須記得要寫成doit()而不是doit。后者只會將函數本身作為值返回。對於對象中的方法也是如此。方法將在下一節講到。

 

A.3對象和相關內容

 

學習下面的內容前,假設讀者已經了解面向對象程序設計的工作原理(否則這一章就沒多大意義了。不過不懂沒有關系,可以不使用對象,或者參見第7章)。

Python中,可以使用class關鍵字定義類,像下面這樣:

class Basket:                                                              
    # 不要忘記self參數
    def __init__(self, contents=None):                                     
        self.contents = contents or [ ]                                    
                                                                           
    def add(self, element):                                                
        self.contents.append(element)                                      
                                                                           
    def print_me(self):                                                    
        result = ""                                                        
        for element in self.contents:                                      
            result = result + " " + repr(element)                          
        print "Contains: " + result

 

上面例子中有些值得注意的的方面。

方法這樣調用:

object.method(arg1, arg2) 

有些參數是可選的,並且被賦予了默認值(在A.2節提到過),通過下面這樣定義函數而實現:

def spam(age=32):
    …

這里的spam函數可以使用1個或0個參數調用。如果不使用參數進行調用,那么參數age會使用默認值32

repr函數將對象轉換 為它的字符串表達形式(如果element包括數字1,那么repr(element)就等同於“1”,這里的“element”是字面量字符串)。

Python內的方法或成員變量(特性)都是無保護的(也不是私有的)。封裝更像是一種編程風格(如果真的需要的話,也可以使用一些命名約定實現私有化,比如使用單或雙下划線作為名稱前綴)。

 

現在來談談短路邏輯.......

Python 內所有的值都可以用做邏輯值。那么空值,比如False[ ]0" " None表示邏輯假,而其他值(比如True[0]1"Hello, world" 表示邏輯真。

邏輯表達式,比如a and b是這樣計算的:

檢查a是否為真。

如果答案是否定的,那么直接返回a

如果為真,那么直接返回b(表示表達式中的真值)。

相應的a or b的邏輯就是這樣的:

如果a為真,那么返回a

否則返回b

短路機制讓你可以像實現布爾運算符那樣使用and或這or,同時也允許程序員編寫短小精干的條件表達式。比如如下語句:

if a:
    print a
else:
    print b

可以寫為如下形式:

print a or b

事實上,這是Python的一種習慣用語,最好還是能習慣它。


注意:在Python 2.5中,已經引入了真正的條件表達式,所以你可以寫成這種形式:

print a if a else b



Basket構造函數(Basket.__init__)使用這個策略處理默認參數。參數contents的默認值是None(也就是假),那么要檢查它是否包含一個值的時候,可以寫成如下形式:

if contents:
    self.contents = contents
else:
    self.contents = [ ]

 

而構造函數只用了一條語句:

self.contents = contents or [ ]

為什么不把[ ]的默認值放在前面呢?這是Python工作方式的原因,它會給所有Basket實例賦予一個同樣的空列表作為默認內容。某個實例開始填充數據,它們會包含同樣的元素,而默認的也不再是空列表。想要學習這方面的更多的知識的話,請參見第5章內有關一致性(identity)和相等性(equality)區別的討論。


注意:

Basket.__init__等方法使用None作為占位符時,使用contents is None作為條件,比只檢查參數的布爾值要安全,因為這樣做允許傳入類似於空列表這樣的假值(到對象外可以保留一個引用的地方)。


 

如果將空列表作為默認值使用,像下面這樣做,避免在實例間共享內容的問題:

def __init__(self, contents=[ ])
    self.contents = contents[:]

能猜到它是如何工作的嗎?並不是每個地方都使用同一個空列表,而是使用contents[:]表達式創建了一個副本(也就是對整個列表進行分片)。

 

那么為了創建一個Basket對象並使用它(調用給它的一些方法),可以像下面這樣做:

b = Basket(['apple', 'orange'])
b.add("lemon")
b.print_me()

這樣會打印Basket的內容——一個apple(蘋果),一個orange(桔子)和一個lemon(檸檬)。

 

除了__init__外還有一些魔法方法。比如__str__方法,它定義對象作為字符串時候輸出。可以用它來替代print_me

def __str__(self):
    result = " "
    for element in self.contents:
        result = result + " " +repr(element)

    return "Contains: " + result

 

如果想打印b,那么只要像下面這樣:

print b

很酷吧?

 

像下面這樣實現子類化(繼承):

class SpamBasket(Basket):
    #

 

Python 允許多繼承,所以可以在圓括號內用逗號隔開多個超類。類像這樣初始化:

x = Basket()

 

而構造函數像我說過的一樣,通過定義特殊的成員函數__init__而得到的。假設SpamBasket有個__init__(self, type)構造函數,那么就能實現一個SpamBasket對象:

y = SpamBasket("apple")

 

如果在SpamBasket的構造函數中,需要調用一個或者多個超類的構造函數,可以這樣調用:Basket.__init__(self)。注意,除了要提供一般的參數外,還要顯式地提供self參數,因為超類的__init__不知道它正在處理哪個實例。

有關更多Python中面向對象程序設計的知識,請參見第7章。

 

A.4 其他瑣碎知識

 

讓我們在結束這個附錄前快速地回顧一些有用的東西。大多數有用的函數和類都在模塊中,它們是真正的以.py作為擴展名並包括Python代碼的文本文件。讀者可以在自己的程序中導入進行使用,比如要使用標准模板math中的sqrt函數,即可以像下面這樣編寫代碼:

import math
x = sqrt(y)

 

也可以像下面這樣:

 
        
from math import sqrt
x = sqrt(y)
 
        

有關更多標准庫模塊的信息,請參見第10章。

所有模塊/腳本內的代碼都會在導入的時候運行。如果想讓你的程序既是可以導入的模塊,又是可以運行的程序,可以在末尾加入下面這行:

if __name__ == "__main__":
    main()

 

這個方法很美妙,如果模塊作為可執行腳本運行(也就是並不導入到其他腳本中),那么函數main會被調用。當然,可以在main函數內可以做任何事。

而如果想要在UNIX內創建可執行腳本的話,可以使用下面這行代碼讓腳本自己運行:

#!/usr/bin/env python

 

最后,簡單地介紹一個重要概念:異常。有些操作(類似於除0或者從不存在的文件中讀取數據)會產生一個錯誤狀況,或者說異常。你可以創建自定義異常,讓它們在適合的時間引發它們。

如果對於異常什么都不做,程序會結束,並且打印錯誤信息。不過可以使用try/except語句避免這種情況。比如:

def safe_division(a, b):
    try:
        return a/b
    except ZeroDivisionError:
        pass

 

ZeroDivisionError是個標准的異常。本例中,可以檢查b是否為0,但是很多情況下,這個方法行不通。除此之外,如果在safe_division中,移除了try/except語句的話,會讓它變成一個調用時帶有風險的函數(就變成unsafe_division了),仍然可以像下面這樣做:

try:
    unsafe_division(a, b)
except:
    print "Something was divided by zero in unsafe division."

本例中,一般來說不會看到具體的問題,但是它可能發生,使用異常可以避免將時間浪費在無謂的測試上。

那么,就是這樣了,希望各位讀者有收獲。開始編程吧。要記得Python的學習箴言:使用源代碼(就是說要閱讀能得到的所有代碼)。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM