# 3. 一個非正式的 Python 簡介

在下面的例子中，輸入與輸出的區別在於有無提示符（prompt，>>> 和 ...）：如果要重做範例，你必須在提示符出現的時候，輸入提示符後方的所有內容；那些非提示符開始的文字行是直譯器的輸出。注意到在範例中，若出現單行只有次提示符時，代表該行你必須直接換行；這被使用在多行指令結束輸入時。

在本手冊中的許多範例中，即便他們為互動式地輸入，仍然包含註解。Python 中的註解 (comments) 由 hash 字元 `#` 開始一直到該行結束。註解可以從該行之首、空白後、或程式碼之後開始，但不會出現在字串之中。hash 字元在字串之中時仍視為一 hash 字元。因為註解只是用來說明程式而不會被 Python 解讀，在練習範例時不一定要輸入。

一些範例如下：

    # this is the first comment
    spam = 1  # and this is the second comment
              # ... and now a third!
    text = "# This is not a comment because it's inside quotes."

## 3.1. 把 Python 當作計算機使用

讓我們來試試一些簡單的 Python 指令。啟動直譯器並等待第一個主提示符 `>>>` 出現。（應該不會等太久）

### 3.1.1. 數字 (Number)

直譯器如同一台簡單的計算機：你可以輸入一個 expression（運算式），它會寫出該式的值。Expression 的語法很使用：運算子 `+`、`-`、`*` 和 `/` 的行為如同大多數的程式語言（例如：Pascal 或 C）；括號 `()` 可以用來分群。例如：

    >>> 2 + 2
    4
    >>> 50 - 5*6
    20
    >>> (50 - 5*6) / 4
    5.0
    >>> 8 / 5  # division always returns a floating point number
    1.6

整數數字（即 `2`、`4`、`20`）為 `int` 型態，數字有小數點部份的（即 `5.0`、`1.6`）為 `float` 型態。我們將在之後的教學中看到更多數字相關的型態。

除法 (`/`) 永遠回傳一個 float。如果要做 floor division 並拿到整數的結果（即去除所有小數點的部份），你可以使用 `//` 運算子；計算餘數可以使用 `%`：

    >>> 17 / 3  # classic division returns a float
    5.666666666666667
    >>>
    >>> 17 // 3  # floor division discards the fractional part
    5
    >>> 17 % 3  # the % operator returns the remainder of the division
    2
    >>> 5 * 3 + 2  # result * divisor + remainder
    17

在 Python 中，計算冪次 (powers) 可以使用 `**` 運算子 1：

    >>> 5 ** 2  # 5 squared
    25
    >>> 2 ** 7  # 2 to the power of 7
    128

等於符號 (`=`) 可以用於為變數賦值。賦值完之後，在下個指示符前並不會顯示任何結果：

    >>> width = 20
    >>> height = 5 * 9
    >>> width * height
    900

如果一個變數未被「定義 (defined)」（即變數未被賦值），試著使用它時會出現一個錯誤：

    >>> n  # try to access an undefined variable
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'n' is not defined

浮點數的運算有完善的支援，運算子 (operator) 遇上混合的運算元 (operand) 時會把整數的運算元轉換為浮點數：

    >>> 4 * 3.75 - 1
    14.0

在互動式模式中，最後一個印出的運算式的結果會被指派至變數 `_` 中。這表示當你把 Python 當作桌上計算機使用者，要接續計算變得容易許多：

    >>> tax = 12.5 / 100
    >>> price = 100.50
    >>> price * tax
    12.5625
    >>> price + _
    113.0625
    >>> round(_, 2)
    113.06

這個變數應該被使用者視為只能讀取。不應該明確地為它賦值 --- 你可以創一個獨立但名稱相同的本地變數來覆蓋掉預設變數和它的神奇行為。

除了 `int` 和 `float`，Python 還支援了其他的數字型態，包含 `Decimal` 和 `Fraction`。Python 亦內建支援複數 (complex numbers)，並使用 `j` 和 `J` 後綴來指定虛數的部份（即 `3+5j`）。

### 3.1.2. 字串 (String)

除了數字之外，Python 也可以操作字串，而表達字串有數種方式。它們可以用包含在單引號 (`'...'`) 或雙引號 (`"..."`) 之中，兩者會得到相同的結果2。使用 `\` 跳脫出現於字串中的引號：

    >>> 'spam eggs'  # single quotes
    'spam eggs'
    >>> 'doesn\'t'  # use \' to escape the single quote...
    "doesn't"
    >>> "doesn't"  # ...or use double quotes instead
    "doesn't"
    >>> '"Yes," they said.'
    '"Yes," they said.'
    >>> "\"Yes,\" they said."
    '"Yes," they said.'
    >>> '"Isn\'t," they said.'
    '"Isn\'t," they said.'

在互動式的直譯器中，輸出的字串會被引號包圍且特殊符號會使用反斜線 (`\`) 跳脫。雖然這有時會讓它看起來跟輸入的字串不相同（包圍用的引號可能會改變），輸入和輸出兩字串實為相同。一般來說，字串包含單引號而沒有雙引號時，會使用雙引號包圍字串。函式 `print()` 會產生更易讀的輸出，它會去除掉包圍的引號，並且直接印出被跳脫的字元和特殊字元：

    >>> '"Isn\'t," they said.'
    '"Isn\'t," they said.'
    >>> print('"Isn\'t," they said.')
    "Isn't," they said.
    >>> s = 'First line.\nSecond line.'  # \n means newline
    >>> s  # without print(), \n is included in the output
    'First line.\nSecond line.'
    >>> print(s)  # with print(), \n produces a new line
    First line.
    Second line.

如果你不希望字元前出現 `\` 就被當成特殊字元時，可以改使用 raw string，在第一個包圍引號前加上 `r` ：

    >>> print('C:\some\name')  # here \n means newline!
    C:\some
    ame
    >>> print(r'C:\some\name')  # note the r before the quote
    C:\some\name

字串值可以跨越數行。其中一方式是使用三個重覆引號：`"""..."""` 或 `'''...'''`。此時換行會被自動加入字串值中，但也可以在換行前加入 `\` 來取消這個行為。在以下的例子中：

    print("""\
    Usage: thingy [OPTIONS]
         -h                        Display this usage message
         -H hostname               Hostname to connect to
    """)

會產生以下的輸出（注意第一個換行並沒有被包含進字串值中）：

    Usage: thingy [OPTIONS]
         -h                        Display this usage message
         -H hostname               Hostname to connect to

字串可以使用 `+` 運算子連接 (concatenate)，並用 `*` 重覆該字串的內容：

    >>> # 3 times 'un', followed by 'ium'
    >>> 3 * 'un' + 'ium'
    'unununium'

兩個以上相鄰的字串值（string literal，即被引號包圍的字串）會被自動連接起來：

    >>> 'Py' 'thon'
    'Python'

當你想要分段一個非常長的字串時，兩相鄰字串值自動連接的特性十分有用：

    >>> text = ('Put several strings within parentheses '
    ...         'to have them joined together.')
    >>> text
    'Put several strings within parentheses to have them joined together.'

但這特性只限於兩相鄰的字串值間，而非兩相鄰變數或表達式：

    >>> prefix = 'Py'
    >>> prefix 'thon'  # can't concatenate a variable and a string literal
      File "<stdin>", line 1
        prefix 'thon'
                    ^
    SyntaxError: invalid syntax
    >>> ('un' * 3) 'ium'
      File "<stdin>", line 1
        ('un' * 3) 'ium'
                       ^
    SyntaxError: invalid syntax

如果要連接變數們或一個變數與一個字串值，使用 `+`：

    >>> prefix + 'thon'
    'Python'

字串可以被「索引 indexed」(下標，即 subscripted)，第一個字元的索引值為 0。沒有獨立表示字元的型別；一個字元就是一個大小為 1 的字串：

    >>> word = 'Python'
    >>> word[0]  # character in position 0
    'P'
    >>> word[5]  # character in position 5
    'n'

索引值可以是負的，此時改成從右開始計數：

    >>> word[-1]  # last character
    'n'
    >>> word[-2]  # second-last character
    'o'
    >>> word[-6]
    'P'

注意到因為 -0 等同於 0，負的索引值由 -1 開始。

除了索引外，字串亦支援「切片 slicing」。索引用來拿到單獨的字元，而切片則可以讓你拿到子字串 (substring)：

    >>> word[0:2]  # characters from position 0 (included) to 2 (excluded)
    'Py'
    >>> word[2:5]  # characters from position 2 (included) to 5 (excluded)
    'tho'

注意到起點永遠被包含，而結尾永遠不被包含。這確保了 `s[:i] + s[i:]` 永遠等於 `s`：

    >>> word[:2] + word[2:]
    'Python'
    >>> word[:4] + word[4:]
    'Python'

切片索引 (slice indices) 有很常用的預設值，省略起點索引值時預設為 0，而省略第二個索引值時預設整個字串被包含在 slice 中：

    >>> word[:2]   # character from the beginning to position 2 (excluded)
    'Py'
    >>> word[4:]   # characters from position 4 (included) to the end
    'on'
    >>> word[-2:]  # characters from the second-last (included) to the end
    'on'

這裡有個簡單記住 slice 是如何運作的方式。想像 slice 的索引值指著字元們之間，其中第一個字元的左側邊緣由 0 計數。則 n 個字元的字串中最後一個字元的右側邊緣會有索引值 n，例如：

     +---+---+---+---+---+---+
     | P | y | t | h | o | n |
     +---+---+---+---+---+---+
     0   1   2   3   4   5   6
    -6  -5  -4  -3  -2  -1

第一行數字給定字串索引值為 0...6 的位置；第二行則標示了負索引值的位置。由 i 至 j 的 slice 包含了標示 i 和 j 邊緣間的所有字元。

對非負數的索引值而言，一個 slice 的長度等於其索引值之差，如果索引值落在字串邊界內。例如，`word[1:3]` 的長度是 2。

嘗試使用一個過大的索引值會造成錯誤：

    >>> word[42]  # the word only has 6 characters
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: string index out of range

然而，超出範圍的索引值在 slice 中會被妥善的處理：

    >>> word[4:42]
    'on'
    >>> word[42:]
    ''

Python 字串無法被改變 --- 它們是 immutable。因此，嘗試對字串中某個索引位置賦值會產生錯誤：

    >>> word[0] = 'J'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object does not support item assignment
    >>> word[2:] = 'py'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object does not support item assignment

如果你需要一個不一樣的字串，你必須建立一個新的：

    >>> 'J' + word[1:]
    'Jython'
    >>> word[:2] + 'py'
    'Pypy'

內建的函式 `len()` 回傳一個字串的長度：

    >>> s = 'supercalifragilisticexpialidocious'
    >>> len(s)
    34

也參考

Text Sequence Type --- str

  字串是 sequence 型別的範例之一，並支援該型別常用的操作。

String Methods

  字串支援非常多種基本轉換和搜尋的方法。

Formatted string literals

  包含有表示式的字串值。

Format String Syntax

  關於透過 `str.format()` 字串格式化 (string formatting) 的資訊。

printf-style String Formatting

  在字串為 `%` 的左運算元時，將觸發舊的字串格式化操作，更多的細節在本連結中介紹。

### 3.1.3. List（串列）

Python 理解數種複合型資料型別，用來組合不同的數值。當中最多樣變化的型別為 list，可以寫成一系列以逗號分隔的數值（稱之元素，即 item），包含在方括號之中。List 可以包合不同型別的元素，但通常這些元素會有相同的型別：

    >>> squares = [1, 4, 9, 16, 25]
    >>> squares
    [1, 4, 9, 16, 25]

和字符串（以及各种内置的 sequence 类型）一样，列表也支持索引和切片:

    >>> squares[0]  # indexing returns the item
    1
    >>> squares[-1]
    25
    >>> squares[-3:]  # slicing returns a new list
    [9, 16, 25]

所有 slice 操作都會回傳一個新的 list 包含要求的元素。這意謂著以下這個 slice 複製了原本 list（淺複製，即 shallow copy）：

    >>> squares[:]
    [1, 4, 9, 16, 25]

List 對支援如接合 (concatenation) 等操作：

    >>> squares + [36, 49, 64, 81, 100]
    [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

不同於字串是 immutable，list 是 mutable 型別，即改變 list 的內容是可能的：

    >>> cubes = [1, 8, 27, 65, 125]  # something's wrong here
    >>> 4 ** 3  # the cube of 4 is 64, not 65!
    64
    >>> cubes[3] = 64  # replace the wrong value
    >>> cubes
    [1, 8, 27, 64, 125]

你也可以在 list 的最後加入新元素，透過使用 `append()` 方法 (method)（我們稍後會看到更多方法的說明）：

    >>> cubes.append(216)  # add the cube of 6
    >>> cubes.append(7 ** 3)  # and the cube of 7
    >>> cubes
    [1, 8, 27, 64, 125, 216, 343]

也可以對 slice 賦值，這能改變 list 的大小，甚至是清空一個 list：

    >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    >>> letters
    ['a', 'b', 'c', 'd', 'e', 'f', 'g']
    >>> # replace some values
    >>> letters[2:5] = ['C', 'D', 'E']
    >>> letters
    ['a', 'b', 'C', 'D', 'E', 'f', 'g']
    >>> # now remove them
    >>> letters[2:5] = []
    >>> letters
    ['a', 'b', 'f', 'g']
    >>> # clear the list by replacing all the elements with an empty list
    >>> letters[:] = []
    >>> letters
    []

內建的函式 `len()` 亦可以作用在 list 上：

    >>> letters = ['a', 'b', 'c', 'd']
    >>> len(letters)
    4

也可以嵌套多層 list （建立 list 包含其他 list），例如：

    >>> a = ['a', 'b', 'c']
    >>> n = [1, 2, 3]
    >>> x = [a, n]
    >>> x
    [['a', 'b', 'c'], [1, 2, 3]]
    >>> x[0]
    ['a', 'b', 'c']
    >>> x[0][1]
    'b'

## 3.2. 初探程式設計的前幾步

當然，我們可以用 Python 來處理比 2 加 2 更複雜的工作。例如，我們可以印出費氏數列的首幾項序列：

    >>> # Fibonacci series:
    ... # the sum of two elements defines the next
    ... a, b = 0, 1
    >>> while a < 10:
    ...     print(a)
    ...     a, b = b, a+b
    ...
    0
    1
    1
    2
    3
    5
    8

這例子引入了許多新的特性。

- 第一行出現了多重賦值：變數 `a` 與 `b` 同時得到了新的值 0 與 1。在最後一行同樣的賦值再被使用了一次，示範了等號的右項運算 (expression) 會先被計算 (evaluate)，賦值再發生。右項的運算式由左至右依序被計算。

- `while` 迴圈只要它的條件為真（此範例：`a < 10`），將會一直重覆執行。在 Python 中如同 C 語言，任何非零的整數值為真 (true)；零為假 (false)。條件可以是字串、list、甚至是任何序列型別；任何非零長度的序列為真，空的序列即為假。本例子使用的條件是個簡單的比較。標準的比較運算子 (comparison operators) 使用如同 C 語言一樣的符號：`<`（小於）、`>`（大於）、`==`（等於）、`<=`（小於等於）、`>=`（大於等於）以及 `!=`（不等於）。

- 迴圈的主體會縮排：縮排在 Python 中用來關連一群陳述式。在互動式提示符中，你必須在迴圈內的每一行一開始鍵入 tab 或者（數個）空白來維持縮排。實務上，你會先在文字編輯器中準備好比較複雜的輸入；多數編輯器都有自動縮排的功能。當一個複合陳述式以互動地方式輸入，必須在結束時多加一行空行來代表結束（因為語法解析器無法判斷你何時輸入複合陳述的最後一行）。注意在一個縮排段落內的縮排方式與數量必須維持一致。

- `print()` 函式印出它接收到引數（們）的值。不同於先前僅我們寫下想要的運算（像是先前的計算機範例），它可以處理複數個引數、浮點數數值和字串。印出的字串將不帶有引號，並且不同項目間會插入一個空白，因此可以讓你容易格式化輸出，例如：

      >>> i = 256*256
      >>> print('The value of i is', i)
      The value of i is 65536

  關鍵字引數 end 可以被用來避免額外的換行符加入到輸出中，或者以不同的字串結束輸出：

      >>> a, b = 0, 1
      >>> while a < 1000:
      ...     print(a, end=',')
      ...     a, b = b, a+b
      ...
      0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

註解

1

  因為 `**` 擁有較 `-` 高的優先次序，`-3**2` 會被解釋為 `-(3**2)` 並得到 `-9`。如果要避免這樣的優先順序以得到 `9`，你可以使用 `(-3)**2`。

2

  不像其他語言，特殊符號如 `\n` 在單 (`'...'`) 和雙 (`"..."`) 括號中有相同的意思。兩種刮號的唯一差別，在於使用單刮號時，不需要跳脫 (escape) `"`（但需要跳脫 `\'`），反之亦同。