看例子,學 Python(二)
看例子,學 Python(三)python
很難說,這篇代碼比文字還多的文章,是否適合初學者。
它源於我的筆記,涉及的可能是簡單核心的概念,也許須要一些編程基礎才能快速理解。
內容方面,力求按部就班,避開細枝末節,注重原理和示例的連續性,儘可能不羅列特性,點到即止。編程
說明:本文僅限於 Python 3。segmentfault
從 Hello, Python!
開始,經過一系列不一樣實現,簡單介紹字符串、函數等概念。數據結構
print("Hello, Python!")
print
是一個內置函數;在 Python 2 裏,print
是一個語句(statement)。
字符串由引號表示,這一點與其它語言相似。
語句末尾不須要結尾符(好比 C 系列語言的分號)。app
print("Hello, " + "Python!") print("Hello, " * 3 + "Python!")
字面字符串即爲對象。
操做符 +
和 *
都對字符串作了重載。編輯器
print('Hello, "Python"!')
字符串能夠用雙引號,也能夠用單引號。順帶也可看出 Python 並無字符類型(char)。
經過單、雙引號的恰當使用,能夠避免沒必要要的字符轉義(escape)。上例若改用雙引號,則裏面的 "
就須要轉義了:函數
print("Hello, \"Python\"!")
def say_hello(): print('Hello, Python!')
函數定義由 def
關鍵字指定。
函數的命名習慣上爲小寫下劃線(xxx\_yyy\_zzz
),變量名也是,類名則是駝峯狀(XxxYyyZzz
)。
Python 以【縮進】組織代碼塊,沒有 C 系列語言的花括號,也沒有 Ruby 那樣的 end
語句。
使用縮進的優勢是,代碼風格比較單一,也就比較統一,沒有諸如 {
是否另起一行的爭論;缺點是沒法自動縮進,不但給編輯器出了難題,也使代碼分享變得相對困難,由於縮進一變,程序就不對了。性能
對應於官方教程第三章。
簡單介紹字符串、列表等概念,爲後續內容作準備。ui
下面由 >>>
打頭的代碼,表示是在交互模式下的演示。
打開命令行,鍵入 python,便可進入交互模式。命令行
>>> s = "Hello!" >>> s 'Hello!'
字符串並無方法(size 或 length)返回長度,取而代之的是內建函數 len
:
>>> len("Hello!") 6
其它序列類型(sequence type)也是如此。
做爲一種序列類型,字符串能夠直接用 for
遍歷。
>>> for c in "Hello!": print(c) ... H e l l o !
注意這裏的變量 c
,雖然表示的是單個字符,其實倒是字符串。前面已經說過,Python 沒有字符類型。
經過幾個內建函數,在交互模式下作一些試驗。
函數 type
:查看對象類型:
>>> type("Hello!") <type 'str'>
函數 help
:查看類型或函數的幫助信息:
>>> help(str) Help on class str in module builtins: class str(object) | str(object='') -> str <省略>
查看 help
本身的幫助信息:
>>> help(help) Help on _Helper in module _sitebuiltins object: <省略>
函數 dir
:列出類的屬性:
>>> dir(str) ['__add__', '__class__', '__contains__', <省略>]
不妨看看 dir
又是什麼:
>>> help(dir) Help on built-in function dir in module builtins: <省略>
類型之間能夠比較:
>>> type("hello") == str True
可是通常不這麼用,通常用 isinstance
,由於後者會考慮到類的繼承關係:
>>> isinstance("hello", str) True
不出意外,類型自身也有類型:
>>> type(str) <class 'type'>
這幾個內建函數,很是稱手,後面會常常用到。
嘗試像 C/C++ 那樣對單個字符賦值:
>>> s = "Hello!" >>> s[-1] = '.' # -1 表示倒數第一個(也即最後一個)字符的下標 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment
錯誤信息顯示:str
對象不支持元素賦值。
方法 replace
也同樣,不會改變原來的字符串,而是返回一個替換後的新字符串:
>>> help(str.replace) replace(...) S.replace(old, new[, count]) -> string Return a copy of string S with all occurrences of substring old replaced by new. If the optional argument count is given, only the first count occurrences are replaced.
>>> s = "Hello!" >>> s.replace('!', '.') "Hello." >>> s "Hello!" # 原對象並無改變
列表(list)是最經常使用的數據結構,相似於 C++ 的 std::vector
。
>>> squares = [1, 4, 9, 16, 25] >>> squares [1, 4, 9, 16, 25] >>> type(squares) <class 'list'>
列表的底層實現並不是鏈表(linked list),因此索引的性能仍是不錯的。
比較特別的地方在於,索引的下標能夠爲負數,好比前面提到 -1
表示倒數第一個元素。
>>> squares[0] 1 >>> squares[-1] 25
切片(slice)截取列表的一段。
>>> squares[1:4] [4, 9, 16]
字符串也能夠切片。
固然,切片返回新序列,原序列保持不變。
由於 Python 的對象是引用計數的,因此要拷貝一個列表,不能簡單的賦值,可是能夠用切片間接實現:
>>> squares[:] [1, 4, 9, 16, 25]
不指定起始和結束下標,就切片整個列表。至關於 squares[0:]
或 squares[0:len(squares)]
。
拼接兩個列表,直接相加便可。
>>> squares + [36, 48] [1, 4, 9, 16, 25, 36, 48]
如前所述,Python 有操做符重載的概念,與 C++ 不無類似之處。
與字符串不一樣,列表是可變的,能夠被修改。
>>> squares[6] = 49 >>> squares.append(64) >>> squares.pop() 49 >>> squares [1, 4, 9, 16, 25, 36]
以「斐波那契數列」爲例,介紹基本的控制語句、函數定義。
0, 1, 1, 2, 3, 5, 8, ... a b a, b a, b
打印 100 之內的數列:
>>> a, b = 0, 1 >>> while a < 100: ... print(a, end='') ... a, b = b, a+b ... 0 1 1 2 3 5 8 13 21 34 55 89 >>>
如下幾點值得一提:
a, b = 0, 1
,能夠簡化代碼,更讓 swap 操做變得異常簡單:a, b = b, a
。while
語句與其它語言相似。print
函數指定 end
參數爲空就再也不換行了,end
缺省爲 '\n'
。函數由關鍵字 def
定義。
把剛纔寫在交互模式下代碼,封裝成 fib
函數,並移到文件 mymath.py
中:
def fib(n): "Print a Fibonacci series up to n." a, b = 0, 1 while a < n: print(a, end='') a, b = b, a+b
那麼,mymath
就是一個模塊(module)。
關於模塊,Python 是這樣定義的:
A module is a file containing Python definitions and statements.
對於模塊,咱們暫時先不作深究,知道經過 import
語句來使用便可,就好像 Java 的 import
或 C++ 的 #include
同樣。
>>> import mymath >>> mymath.fib <function fib at 0x7fd1d6ec25f0> >>> mymath.fib(100) 0 1 1 2 3 5 8 13 21 34 55 89 >>> fib = mymath.fib >>> fib(100) 0 1 1 2 3 5 8 13 21 34 55 89
函數也是對象,能夠賦值給變量,做爲參數傳遞。這比 C/C++ 裏的函數指針更強大。
前面定義 fib
時,函數體前有一個字符串:Print a Fibonacci series up to n
,不知道你注意沒有?
它就是文檔字符串,既能夠充當註釋,又是函數對象的一部分,你能夠經過屬性 __doc__
訪問:
>>> fib.__doc__ 'Print a Fibonacci series up to n.'
文檔字符串的功能不言而喻,它爲函數 help
提供了萃取信息的通道。
>>> help(fib) Help on function fib in module mymath: fib(n) Print a Fibonacci series up to n.
若是文檔字符串有多行,可使用三重引號的字符串:
def fib(n): """Print a Fibonacci series up to n. E.g., fib(10) prints: 0 1 1 2 3 5 8 """
只要是函數,都有返回值,沒有明確指定返回值的,就返回 None
。None
是 Python 的空值,至關於 C++ 的 NULL
或 Java 的 null
。
>>> fib(0) >>> print(fib(0)) None
直接打印結果的函數,並非一個好的設計,對於 fib
來講,把結果以列表返回要實用得多。
def fib(n): result = [] a, b = 0, 1 while a < n: result.append(a) a, b = b, a+b return result
改寫 fib
函數,返回數列中的第 N 個數。
def fib(n): a, b = 0, 1 if n <= 0: return 0 if n == 1: return 1 while n > 1: a, b = b, a+b n -= 1 return b
Python 的 if else
縮寫爲 elif
。
Python 沒有 ++
或 --
操做符,可是有 +=
和 -=
。
遞歸和循環比較,遞歸易理解,循環更高效。
def fib(n): if n <= 0: return 0 if n == 1: return 1 return fib(n-1) + fib(n-2)
各位能夠暫停一下,拿階乘(factorial)練練手,下面先給出輪廓:
def fac(n): """ ... >>> fac(4) 24 """ pass
pass
是佔位符,用來標記空代碼塊,純粹爲了經過「編譯」。
參考實現:
def fac(n): """C-style implementation""" result = 1 while n > 1: result = result * n n -= 1 return result
range
表示一段範圍,好比 range(2, n)
就表示從 2
一直到 n-1
(不包括 n
)。
def fac(n): result = 1 for i in range(2, n+1): result *= i return result
回到前面遍歷字符串的演示:
>>> s = "Hello!" >>> for c in s: print(c)
若是須要索引,用 enumerate
:
>>> for i, c in enumerate(s): ... print("s[{}] = {}".format(i, c)) ... s[0] = H s[1] = e s[2] = l s[3] = l s[4] = o s[5] = !
用 range
也能達到目的:
>>> for i in range(len(s)): ... print("s[{}] = {}".format(i, s[i]))
再看幾個 range
的例子:
>>> range(10) # 起點默認爲 0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(0, 10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> range(0, 10, 3) # 步長爲 3 [0, 3, 6, 9]
最後再來看一下 range
的幫助信息:
>>> help(range) range(...) range(stop) -> list of integers range(start, stop[, step]) -> list of integers <省略>
如前所述,函數 help
是很是稱手的。