# 語言基礎 ###### tags: `python` ## 標準輸入與輸出 #### 標準輸出函式:`print()` 用來將資料輸出到終端(terminal)畫面上。 ``` print('Hello Python') ``` 會看到輸出: ``` Hello Python ``` 可以輸出多筆資料,每筆資料使用逗號「,」隔開: ``` print('Hello Python', 2021) print('Today', 'is', 'Sunday') ``` 會看到輸出: ``` Hello Python 2021 Today is Sunday ``` > **注意** > > 使用單引號「'」或雙引號「"」包住的資料在Python中稱為「字串」,只要是文字都必須使用單引號或雙引號在左右兩邊包圍著,而且也必須這麼做,否則會出現錯誤,而數字則是沒有使用單引號或雙引號包圍的數字。 > > 在Python中如果數字左右兩邊有使用班引號或雙引號包圍著,對Python來說,它會是一個字串,而不是數字。 #### 標準輸入函式:`input()` 用來從終端視窗上接收使用者的輸入,輸入的資料為字串型態。 ``` a = input() print(a) ``` 1. 執行後畫面會停住,程式碼會暫停在`input()`該行等待使用者輸入,並按下「Enter」結束輸入的動作。 2. 使用者完成輸入後`input()`函式會傳回使用者的資料,此時需要使用指派運算子「=」,將資料存到變數(也就是電腦的記憶體)中,以避免程式碼往下執行時,資料消失,上面範例中`a`即為該變數名稱,透過`print()`函式,就可以將`a`的內容顯示到標準輸出。 可以在等待使用者輸入時,顯示提示文字: ``` a = input('請輸入您的姓名:') print('您的姓名為:', a) ``` ## 基本資料型態 ### Python基本資料型態(或稱為內建型態) 有: - 數值型態(Numeric type) - `int`, `float`, `bool`, `complex` - 字串型態(String type)- `str` - 容器型態(Container type) - `list`, `set`, `dict`, `tuple` > Python 3後,整數型態一率為int,不再區分整數(int)與長整數(long),而且整數的長度沒有限制。 #### 數值型態 ##### 整數型態 - int Python 3後,整數型態一率為int,不再區分整數(int)與長整數(long),而且整數的長度沒有限制。 - 十進位整數:預設的整數位數,例如:9、89、135等等。 - 二進位整數:在數字前加上0b或0B,後面接上0~1的數字,例如:0b0001、0B10011100。 - 八進位整數:在數字前加上0o或0O,後面接上1~7的數字,例如:0o6、0O163。 - 十六進位整數:在數字前加上0x或0X,後面接上1~9以及A~F的數字,例如:0x1A、0X8C60。 從Python 3.6開始,數字可以加上底線,這對很長的整數閱讀上,會很有幫助。 例如: ``` 1_000_000_000 0x12_34_56_78 0b1000_1101_0101 ``` ##### `print()`函示 為了可以輸出結果到終端機視窗,可以使用`print()`函示,如果有多個結果同時輸出,可以使用逗號`,`分隔。 例如: ``` print(234) print('Hello!', 456) # 同時有多個結果要一次輸出 ``` 會輸出: ``` 234 Hello! 456 ``` 如果想要輸出多的字串時,每個字串用逗號「`,`」做分隔,可以加上`sep=', '`,例如: ``` print('Hello!', '456', sep=', ') ``` 會輸出: ``` Hello!, 456 ``` `print()`函式預設輸出後一定會做換行,如果不想換行,可以指定`end=''`,例如: ``` print("Hello, ", end='') print("World!") ``` 會輸出: ``` Hello, World! ``` ##### `type()`函式 無論是十進位、二進位、八進位、十六進位整數,都是int類別,如果想知道某種資料的型態,可以使用`type()`函式來取得,並搭配`print()函式`來顯示到終端機視窗上。 例如: ``` print(type(10)) print(type(0b1001)) print(type(0o123)) print(type(0x9C)) ``` 終端機視窗會看到這樣的結果: ``` <class 'int'> <class 'int'> <class 'int'> <class 'int'> ``` ##### 浮點數 浮點數是`float`型態,也就是帶有小數點得的數字。 例如: ``` 3.14159 6.0 ``` ##### 複數 複數的形式為`a + bj`,型態為`complex`,複數可以直接做運算。 例如: ``` print(3 + 2j + 5 + 6j) print(type(5j)) ``` 會輸出: ``` 8 + 8j <class 'complex'> ``` ### 布林型態 布林型態的值只有`True`和`False`兩種,為`bool`型態,`True`代表的是「真」,而`False`代表的是「假」。 使用`type()`函式: ``` print(type(True)) print(type(False)) ``` 會輸出: ``` <class 'bool'> <class 'bool'> ``` > 請注意`True`和`False`兩個單字的第一個字母都必須為大寫,不可為小寫。 ### 字串型態 Python中要表示字串,可以使用一對單引號' '或一對雙引號" "來包圍要表示的文字。 例如: ``` 'Hello, World!' '+886-1234567' ``` 單引號和雙引號的功用一樣,可以視情況做互換,例如字串本身包含有單引號時,就可以用雙引號來包圍字串。 例如: ``` "I'm a good student" 'Here is my "STUFF"!!' ``` 字串裡定義了一些特殊的轉義文字,有特殊功用或意義,不會直接在畫面上輸出。 | 符號 | 說明 | | ---------- | -------------------------------------------------- | | `\\` | 反斜線`\` | | `\'` | 單引號`'`' | | `\"` | 雙引號`"` | | \ooo | 以8進位字元碼顯示字元,最多三位數,例如:`\101' | | \xhh | 以8位元16進位字元馬顯示指定字元,例如:\xE8 | | \uhhhh | 以16位元16進位字元馬顯示指定字元,例如:\u32E8 | | \Uhhhhhhhh | 以32位元16進位字元馬顯示指定字元,例如:\U000032E8 | | \0 | 空字元,而不是空字串,等同於`\x00` | | \n | 換行 | | \r | 歸位(同一行) | | \t | TAB | ``` 'Hi,\nGood Morning' "1\t2\t3" ``` 如果字串內想要顯示像`\t`這樣的字串的話,必須寫成`\\t`或是可以在字串前面加上`r`代表直接使用原始字串而不需要轉義,例如: ``` print('\\t') print(r'\t') ``` 輸出為: ``` \t \t ``` 在使用單引`' '`號或雙引號`" "`表示字串時,程式碼不可以換行,如果字串內容必須換行,可以使用`\n`或三重引號,在三重引號內輸入的任何內容和格式都會被如實保留,例如:換行、縮排等等。 ``` print('''This is Aaron's book, May I talk to Amber. Good morning~!```) ``` 輸出為: ``` This is Aaron's book, May I talk to Amber, Good morning~! ``` > Python本身不支援多行註解,但是因為三重引號內可以被輸入任何內容,因此如果有暫時不想執行的程式碼都可以用三重引號來包圍,變相作為多行註解使用。 ##### 練習 下面數字是什麼型態? ``` 0xf 0.0 0o8 '4.4' 3.1e-1 999 0a 0b110 ``` #### 字串格式化 Python有三種格式化字串的方式,用來讓字串可以根據不同的時間顯示不同的結果。 ##### 第一種:%格式 像C風格一樣的格式化字串方式,例如: ``` print('Python version: %.2f' % (3.9)) print('I\'m %d years old, and you are %d.' % (18, 19)) print('Hello %s!' % ('Aaron')) ``` 輸出: ``` Python version: 3.90 I'm 18 years old, and you are 19. Hello Aaron! ``` > 舊方法,看看就好。 ##### 第二種:str.format() [PEP 3101](https://www.python.org/dev/peps/pep-3101/) 定義了透過呼叫 `str.format()`方法來格式化字串。 ``` print('Python version: {}'.format(3.9)) print('I\'m {} years old, and you are {}.'.format(18, 19)) print('Hello {}!'.format('Aaron')) ``` > 舊方法,看看就好。 ##### 第三種:f-string(推薦) [PEP 498](https://www.python.org/dev/peps/pep-0498/)定義了最新的f-string,名稱為:**Literal String Interpolation**,可以在字串裡面直接使用變數,使用起來最直覺。 ``` ver = 3.9 years1 = 18 years2 = 19 name = 'Aaron' print(f'Python version: {ver}') print(f'I\'m {years1} years old, and you are {years2}.') print(f'Hello {name}!' ``` > 從今天起開始使用它。 > **注意** > > 字串的最前面要要加上`f`,表示這是一個f格式的字串。 #### r, u, b字串 ##### r字串 r為raw的意思,字串前面加`r`代表這是一個不需要轉譯符號(例如:`\n`)的字串,所有的轉譯符號都會是普通的文字,例如: ``` print(r'這不是換行\n這不是換行') ``` 會輸出: ``` 這不是換行\n這不是換行 ``` ##### u字串 u為unicode的意思,表示這是一個unicode(國際通用字串編碼)的字串,通常用在像一個中文字需要多個位元組來表示的編碼,如果字串出現亂碼,則可以使用`u`字串,例如: ``` print(u'這是一個unicode字串') ``` > Python 3.x對unicode支援比較好,預設就是unicode,在Python 2.x的字串預設會是以bytes字串在運作。 ##### b字串 b為byte的意思,代表這是一個位元組(byte)組成的字串,例如: ``` print(b'abc') ``` #### `'''`和`"""`包住的字串 三重引號可以用來表示多行字串,預設會==無視轉譯字元==並且像==換行或TAB之類的格式也都會被保留==,例如: ``` print(''' 這是一個三重引號的字串 不需轉譯字元就可以換行 TAB也會被如實保留 ''') ``` 會輸出: ``` 這是一個三重引號的字串 不需轉譯字元就可以換行 TAB也會被如實保留 ``` > **注意** > > 從第一個三重引號開始就是第一行文字了,最後一個三重引號也會佔據一行,所以該範例總共會輸出五行的字串。 單純三重引號包圍住的文字並不會被執行,所以也常常被用來當作多行程式碼註解使用,例如: ``` """ 這是註解 這是註解 這是註解 """ ``` ### 型態轉換 ##### `int()` 如果想將字串、浮點數、布林等型態轉換成整數,可以使用`int()`函式來作轉換。 整數形態和字串型態無法直接做運算,就必須經過轉換。 例如: ``` print(3 + int('9')) print(int('88') + 12) ``` 輸出: ``` 12 100 ``` ##### `bin()`、`oct()、hex()` 如果想直接輸出二進位、八進位、十六進位整數到畫面上,可以這樣做: ``` print(bin(10)) print(oct(10)) print(hex(10)) ``` 會輸出: ``` 0b1010 0o12 0xa ``` 其輸出的資料型態皆為字串,例如使用`type()`函式來得到其資料型態: ``` print(type(oct(10))) print(type(hex(10))) ``` 會輸出: ``` <class 'str'> <class 'str'> ``` 當我們使用`int()`函式從字串建立整數時,可以指定其基底為2進位、8進位或16進位。 例如: ``` print(int('10', 2)) print(int('10', 8)) print(int('10', 16)) ``` 會輸出: ``` 2 8 16 ``` 需注意,如果要將`'3.14'`這樣的字串透過`int()`取得整數部分會出現`ValueError`錯誤,必須先使用`float()`轉為福點數後再用`int()`取得整數部分。 ##### `float()` 可以將字串轉為浮點數型態。 ##### `bool()` `bool()`內可以傳入任何型態,只要傳入的是:`None、False、0、0.0、0j(複數)、''(空字串)`等等,都會回傳`False`,這些型態以外的的其他值傳入`bool()`,都會回傳`True`。 ##### `str()` 可以將數值形態的資料轉換成字串型態。 ##### `ord()` 顯示某個字元的編碼,例如: ``` ord('哈') #輸出:21704 ``` ##### `chr()` 將文字編碼轉為文字顯示,例如: ``` chr(21704) # 輸出:'哈' ``` ##### 練習 ㄧ、下面有一程式,使用者輸入兩個數字,加總後顯示到標準輸出上: ```python a = input('請輸入數字1:') # 程式會停在這裡等待使用者輸入 b = input('請輸入數字2:') # 程式會停在這裡等待使用者輸入 print('總和是: ' + a + b) ``` 此程式執行結果為: ``` 請輸入數字1: 3 請輸入數字2: 5 總和是: 35 ``` 正確執行結果應該為: ``` 請輸入數字1: 3 請輸入數字2: 5 總和是: 8 ``` 請問該怎麼修改程式碼? > 請使用轉型函式來解決問題 > 二、下面有一程式,使用者輸入一個帶有小數點的數字,保留小數點兩位後輸出到標準輸出: ``` a = input('請輸入一個小數數字: ') print('保留小數兩位數: ' + a) ``` 請問該怎麼修改程式碼? > 請使用型態轉換來解答問題 ## 群集型態 在開發過程當中,常常會需要收集一些資料後一起做處理,這些資料根據用途不同可能會使用不同的資料結構來做收集,例如可能會需要資料依照順序排列、需要資料不重複、需要每筆資料都有對應的的鍵值(key value)來做存取等等,相比其他程式語言需要使用特定的函式或類別來做建立,Python提供了語法上的直接支援,因此使用起來會更容易且方便。 ### 清單(list) 清單的型態是list,其特色為: - 有序(sorted) - 索引(index) - 內容可變 - 長度可變 清單可以使用`[ ]`來建立,裡面每個元素使用逗號「,」做區隔。 > 可以透過索引來取得指定元素值,起始為0,代表第一個元素,如:`a[0]`代表a的第一個元素值。 例如: ``` [1, 2, 3] ['Aaron', 'Apple', 'Amber', 'Astrid'] [3.4, True] # list內的元素可以是相異的資料型態 [] # 建立長度為0的清單 ``` ``` print([1, 2, 3]) print([1, 2, 3][0]) print([1, 'Aaron', True, 3.3, 'Today']) print([1, 'Aaron', True, 3.3, 'Today'][4]) ``` 會輸出: ``` [1, 2, 3] 1 [1, 'Aaron', True, 3.3, 'Today'] Today ``` 清單方法: | 方法名稱 | 說明 | | ----------- | -------------------------- | | `append()` | 新增一筆資料到清單的最後面 | | `remove()` | 移除清單內某個元素值 | | `reverse()` | 將清單內元素順序反過來 | | `sort()` | 排序清單 | | `extend()` | 新增多筆資料到清單 | 例如: ``` a = [1, 2, 3,] # 最後一個逗號可以省略,如: [1, 2, 3] a.append(999) a.append(999) a.append(999) a.append('abc') a.append(False) print(a) print(a[4]) a[4] = 'xxx' print(a) a.remove(999) a.remove('abc') a.reverse() a = [3, 2, 6,0, 1, 9] a.sort() a.extend('abcde') print(len(a)) a.append(0) print(len(a)) print(a) ``` 會輸出: ``` [1, 2, 3, 999, 999, 999, 'abc', False] 999 [1, 2, 3, 999, 'xxx', 999, 'abc', False] 11 12 [0, 1, 2, 3, 6, 9, 'a', 'b', 'c', 'd', 'e', 0] ``` 範例2: ``` nums = [1, 2, 3] print(nums) nums.append(4) print(nums) print(nums[0]) nums[3] = 0 print(nums) nums.remove(0) print(nums) ``` 輸出為: ``` [1, 2, 3] [1, 2, 3, 4] 1 [1, 2, 3, 0] [1, 2, 3] ``` ###### 群集型態通用方法 通用方法可以使用在Python支援的各種群集型態上: | 方法名稱 | 說明 | | -------- | ------------------------------------ | | `len()` | 取回該群基資料的長度(共有幾筆資料) | | `del` | 刪除指定索引位置的元素 | | `in` | 判斷資料是否存在於該群集資料中 | > `remove()`方法和`del`都是刪除元素,但是`remove()`是根據給定的元素值來做判斷,而`del`是給定指定的位置,容易混淆,還請多加注意。 範例: ``` nums = [1, 2, 3] del nums[0] print(nums) print(len(nums)) print(4 in nums) ``` 輸出為: ``` [2, 3] 2 False ``` 另外,你也可以使用`list()`方法來將其它群集資料轉成`list()`型態。 ``` print(list('abcdef')) ``` 會輸出: ``` [a, b, c, d, e, f] ``` > 可以使用`list()`函式來轉換成清單型態的資料必須是可迭代(iterable)的物件,像是字串、集合(set)或Tuple(tuple)等等,關於可迭代的的含義,之後的的章節會另外說明。 ##### 練習 請將: ``` [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ``` 透過清單的操作,變成: ``` [8, 6, 4, 2, 0, 'ok'] ``` 並輸出到終端畫面上。 ### 集合(set) 集合這個群集資料結構裡面的內容沒有順序且元素不會重複,可以使用`{ }`來建立集合,建立時每個元素以逗號「,」分開來,如果建立的時候有重複的元素,則只會保留一個,重複的都會被去除,例如: ``` print({'A', 'B', 'C'}) my_set = {1, 2, 3, 1, 2, 3} print(my_set) ``` 會輸出: ``` {'A', 'B', 'C'} {1, 2} ``` 如果要建立空的集合,並不是使用`{}`,這會建立一個空的字典(dict),而是要呼叫`set()`函式,例如: ``` my_set = set() ``` 集合的方法: | 方法名稱 | 說明 | | ---------- | ---------------------------------------------- | | `add()` | 新增一個元素 | | `remove()` | 刪除元素 | | `update()` | 新增多個元素,參數可以是list、set、tuple和字串 | 而上一小節提到的通用方法`len()、in`也可以用在集合上面,例如: ``` my_set = {1, 2, 3} my_set.add(4) my_set.add(3) print(my_set) my_set.remove(3) print(my_set) print(len(my_set)) print(3 in my_set) ``` 會輸出: ``` {1, 2, 3, 4} {1, 2, 4} 3 False ``` 由於集合必須保證內容的不重複,所以並非所有資料型態的元素都可以放進去,例如:清單和集合就都不行。 ``` {[1, 2, 3]} {{1, 2, 3}} ``` 會輸出: ``` TypeError: unhashable type: 'list' TypeError: unhashable type: 'set' ``` 要從清單、字串或Tuple建立集合,也可以使用`set()`函式,例如: ``` print(set('ABCDE')) print(set([1, 2, 3])) print(set((1, 2, 3))) ``` 會輸出: ``` {'A', 'B', 'C', 'D', 'E'} {1, 2, 3} {1, 2, 3} ``` 其他範例: ``` a = {0, 1, 2, 3, 1, 2, 3, 4, 5, 3, 4} a = set() print(a) print(type(a)) a.add('A') a.add('A') a.add(True) a.add(44) a.remove(44) print(a) print(len(a)) a = [1, 2, 3] a.append({'A', 'B'}) print(a[3]) ``` 會輸出: ``` set() <class 'set'> {True, 'A'} 2 {'A', 'B'} ``` 清單跟集合可以互相轉換: ``` a = list({0, 1, 2}) print(a) a = set([0, 1, 2]) print(a) a = set('abc') print(a) ``` 會輸出: ``` [0, 1, 2] {0, 1, 2} {'a', 'c', 'b'} ``` ##### 練習 請依序寫出下面需求的程式碼,執行後顯示第八項的結果到終端畫面上: 1. 建立一個清單,裡面有5個元素1, 2, 3, 4, 5,並指定給a變數。 2. 將清單第一個元素修改為0 3. 將清單最後一個元素修改為0 4. 將0從清單裡去除 5. 將清單由大到小排序 6. 將清單專換成集合 7. 加入2和3兩個數字到集合 8. 集合內現在有幾個元素? ### 字典(dict) 字典用來儲存兩兩對應鍵(key)與值(value),型態為dict,建立時可以使用`{ }`以及冒號「:」,鍵在左,值在右的格式,例如: ``` phones = {'Aaron': '+886-1234567', 'Amber': '+886-7654321'} print(phones['Aaron']) ``` 上面範例會建立兩筆dict資料,'Aaron'和'Amber'為鍵,'+886-1234567'和'+886-7654321'為各自的值;透過鍵來取得值,該範例會輸出: ``` +886-1234567 ``` > 注意: > > 1. 鍵不可以重複。 > 2. 透過`[]`來取得鍵所對應的值。 > 3. `del`可以刪除某個鍵與值。 > 4. `in`可以判斷該鍵是否存在。 如果透過`[]`取出值時該鍵不存在,會發生`KeyError`的錯誤,可以使用`in`先判斷該鍵是否存在,例如: ``` data = {'A': 123, 'B': 456, 'C': 789} print(data) del data['B'] print(data) print('B' in data) ``` 會輸出: ``` {'A': 123, 'B': 456, 'C': 789} {'A': 123, 'C': 789} False ``` 字典的方法: | 方法名稱 | 說明 | | ---------- | ---------------------------------- | | `get()` | 取得指定鍵的值 | | `items()` | 取得每一對鍵值,會回傳`dict_items` | | `keys()` | 取得所有的鍵,會回傳`dict_keys` | | `values()` | 取得所有的值,會回傳`dict_values` | ``` data = {'A': 123, 'B': 456, 'C': 789} print(data.items()) print(data.keys()) print(data.values()) ``` 會輸出: ``` dict_items([('A', 123), ('B', 456), ('C', 789)]) dict_keys(['A', 'B', 'C']) dict_values([123, 456, 789]) ``` 除了使用`{}`建立字典外,也可以使用`dict()`和`fromkeys()`函式來建立字典,例如: ``` data = dict(A = 123, B = 456, C = 789) # 等同於data = {'A': 123, 'B': 456, 'C': 789} data2 = data.fromkeys(['A', 'B'], '000') print(data) print(data2) ``` 會輸出: ``` {'A': 123, 'B': 456, 'C': 789} {'A': 000, 'B': 000} ``` > 透過dict()方法建立字典,鍵不需要用大括號包圍,且不能給重複的鍵。 ##### 練習 ``` a = {'A': 1, 'B': 2, 'C': 3} ``` 1. 將鍵為'B'的值改為5 2. 將鍵為'C'的值轉型成字串 3. 刪除鍵為'A'的該筆資料 4. 新增鍵'D',設定其值為99 5. 新增鍵'E',設定其值為一清單,該清單內有2和3兩個值 6. 計算a這個字典目前有幾組元素 7. 取出a字典內所有的值,用清單存放,並設定給b變數 答案: ``` a['B'] = 5 print(a) a['C'] = str(a['C']) print(a) del a['A'] print(a) a['D'] = 99 print(a) a['E'] = [2, 3] print(a) print(len(a)) b = list(a.values()) print(b) ``` ### Tuple(tuple) Tuple很多地方跟list類似,如:有順序性、可以使用`[]`來存取元素,但是Tuple在建立後就不可以修改內容,建立Tuple有兩個直接支援的語法:直接在某個值後面加上「逗號`,`」或是使用一對小括號`()`,例如: ``` a = 10, print(a) b = 10, 20, 30 print(b) c = 'Aaron', 10, True print(c) d = (100, 101, 102) print(d) print(d[0]) type(d) ``` 會輸出: ``` (10, ) (10, 20, 30) ('Aaron', 10, True) (100, 101, 102) 100 <class 'tuple'> ``` > 1. 雖然用逗號就可以建立Tuple,但是用小括號的話更可以讓人容易一眼就看出其型態。 > > 2. 建立只有一個元素的Tuple不可以使用小括號,而要使用逗號,例如: `(elem)`不行,`elem, `可以。 > 3. 事實上,之前在建立list、set、dict時也都是省略了最後一個逗號,所以如果之後有看到逗號,就不用太訝異。 Tuple內的元素可以做拆解(Unpack)指定給不同的變數,例如: ``` a, b, c = (10, 20, 30) print(a) print(b) print(c) ``` 會輸出: ``` 10 20 30 ``` 因為Tuple的括號是可以省略的,所以有可能會看到下面這樣的寫法: ``` a, b, c = 10, 20, 30 a, b = b, a print(a) print(b) ``` 會輸出: ``` 20 10 ``` > 拆解元素的特性同樣可以用在list、set上面,例如:`x, y, z = [1, 2, 3]`或`x, y, z = {1, 2, 3}` 除了拆解(Unpack)元素之外,還有個進階拆解元素功能(Extended Iterable Unpacking),例如: ``` a, *b = (1, 2, 3, 4, 5) print(a) print(b) a, *b, c = [1, 2, 3, 4, 5] print(a) print(b) print(c) ``` 會顯示: ``` 1 [2, 3, 4, 5] 1 [2, 3, 4] 5 ``` 在某個變數上指定`*`後,其他變數會被分配單一值,剩下的元素會以list的型態指定給標上星號的變數。 ``` a = (1, 2, 3) # b = a[0] # c = a[1] # d = a[2] b, c, d = a # 等同上面三行 print(b, c, d) b, c, d = [4, 5, 6] print(b, c, d) b, c, d = {7, 8, 9} print(b, c, d) b, c, *d = 1, 2, 3, 4, 5, 6 print(b, c, d) b, *c, d = 1, 2, 3, 4, 5, 6 print(b, c, d) ``` 會輸出: ``` 1 2 3 4 5 6 8 9 7 1 2 [3, 4, 5, 6] 1 [2, 3, 4, 5] 6 ``` ### 群集型態快速比較 | | List | Set | Dict | Tuple | | -------- | :----------------: | :------: | :--------------: | :---------: | | 建立 | []、list() | set() | {}、dict() | ()、tuple() | | 新增資料 | append()、extend() | add() | [] | n/a | | 查詢 | [] | n/a | get()、[] | [] | | 修改 | [] | n/a | [] | n/a | | 刪除 | remove()、del | remove() | del | n/a | | 判斷存在 | if-in | if-in | has_key()、if-in | if-in | ## 變數與運算子 ### 變數 在寫程式時,我們會經過很多運算來得到結果,香蕉每斤20元,想要得到10斤、20斤、30斤要多少錢,例如: ``` print('香蕉10斤價格:', 20 * 10) print('香蕉20斤價格:', 20 * 20) print('香蕉30斤價格:', 20 * 30) ``` 一週後香蕉每斤價格變動了,必須每一行修改程式碼,如果說程式裡有10個地方都需要計算香蕉的價格,那就必須修改10個地方,如果漏掉一個地方,程式的執行結果就會出現錯誤。是不是有個更方便的辦法可以更快的修改並且降低錯誤呢?答案就是使用「變數」,請看下面程式碼: ``` banna_price = 20 print('香蕉10斤價格:', banna_price * 10) print('香蕉20斤價格:', banna_price * 20) print('香蕉30斤價格:', banna_price * 30) ``` 這裡的執行結果會和上一次的程式碼一樣,但是,未來香蕉每斤價格改變了,只需要修改`banna_price`後面的數字,不管有多少行,因為全部都會使用`banna_price`內存放的20來做計算,所以都會跟著反映在執行結果上,減少了修改可能造成的錯誤,並且幫20取了一個有意義的名字,而非不明意義的魔術數字。 `banna_price`被稱為變數(variable),透過等號「=」號,我們將20存到變數裡面,這個變數的值就相當於20,之後,就可以直接拿變數來做運算。 Python屬於動態型別語言,變數本身沒有型態,且可以不需要經過宣告,在第一次透過「=」號指定值的時候就是建立了一個變數,如果在建立之前,嘗試存取變數,會出現`NameError`的錯誤,例如: ``` print(x) ``` 會輸出: ``` NameError: name 'x' is not defined ``` ##### 變數命名規則 1. 可以使用英文字母大寫及小寫,大小寫代表不同的變數。 > 例如:`a`和`A`是不同的變數名稱。 2. 可以使用數字,但第一個字不能是數字。 > 例如:`1abc`為錯誤命名,`abc1`為合法名字。 3. 可以使用底線,第一個字為底線的話,有其特殊意義,請了解後再使用。 > 例如: > > - 底線開頭的變數通常為隱藏的變數,不打算給外部使用。 > - 開頭連續兩個底線的變數,代表其唯一性,不可被修改。 4. 不可以使用保留字。 > 保留字: > > If、elif、else、and、or、not、import、from、as、assert、for、while、break、continue、try、except、finally、pass、def、return、lambda、del、global、nonlocal、in、is、with、yield、class、None、True、False ##### `id()` Python內,變數始終都會是參考(reference),透過等號只是把參考指定給變數,可以呼叫`id()`函式來取得變數的記憶體位址,例如: ``` x = 10 y = x print(id(x)) print(id(y)) ``` 可能的輸出如下(因電腦不同,記憶體位址可能會與這裡的輸出不同,但兩個變數的記憶體位置會一樣): ``` 289012347 289012347 ``` 一開始`x`參考到了10這個整數物件,也就是`x`裡存放的是10的物件參考,接著把`x`內存放的參考也放到`y`變數內,所以`y`變數也參考到10物件,也就是同一個物件。 在看下面範例: ``` x = 1 print(id(x)) x = x + 1 print(id(x)) ``` 會輸出: ``` 18090383000 18094327699 ``` 一開始`x`參考到1這個物件,接著`x`參考的內容加上1之後會產生一個新的物件,然後透過等號將新的物件參考在指定給`x`,`x`內舊的參考會被覆蓋成新的參考。 在看下面範例: ``` x = [1, 2, 3] print(x) y = x y[0] = 0 print(x) ``` 輸出: ``` [1, 2, 3] [0 ,2, 3] ``` 在指定`y = x`的時候,兩個變數因為參考到同一個物件,所以將`y[0]`改為0後,原本的`x`內的元素0也跟著改變了。 ##### `is、is not` 除了使用`id()`函式來觀察變數參考的記憶體之外,還可以使用`is`指令來確認兩個變數是否參考到同一物件,用`is not`來判兩個變數參考是否不一樣。 ``` x = 3 y = x print(x is y) y = 20 print(x is y) ``` 會輸出: ``` True False ``` 變數本身沒有型態,可以對著同一個變數指定不同形態的值,當呼叫變數的某個方法的時候,只要確定方法存在就不會出現錯誤,例如`list`和`tuple`兩種型態都有查詢元素位置的`index()`方法,因此下面的程式碼不會出錯: ``` x = [1, 2, 3] print(x.index(2)) x = (1, 2, 3) print(x.index(2)) ``` 當不再需要某個變數,可以呼叫`del`來刪除它,例如: ``` x = 10 del x print(x) ``` 會輸出: ``` NameError: name 'x' is not defined ``` 會出現錯誤,因為`x`變數已經被刪掉了。 ### 算數運算子 算術運算子有: | 運算子 | 說明 | | ------ | ---------------------- | | + | 加法運算 | | — | 減法運算 | | * | 乘法運算 | | ** | 指數運算 | | / | 除法運算 | | // | 除法運算,但只保留整數 | | % | 除法運算,但是只取餘數 | ##### 數值的運算 ``` print(1 + 2) print(1 - 2) print(1 * 2) print(2 ** 3) print(1 / 2) print(1 // 2) print(1 % 2) ``` 會輸出: ``` 3 -1 2 8 0.5 0 1 ``` 需注意小數點的運算可能會出乎意料: ``` print(0.1 + 0.1 + 0.1) print(1.0 - 0.8) print(0.1 + 0.1 + 0.1 == 0.3) ``` 會輸出: ``` 0.30000000000000004 0.19999999999999996 False ``` 這並不是Python程式語言的錯誤,而是Python遵守IEEE 754浮點運算標準,而這個運算標準因為使用分數和指數來表示,所以會有浮點數誤差。 如果對小數運算的精度要求很高的話,可以使用`decimal.Decimal`類別來做運算,例如: ``` import decimal d1 = decimal.Decimal('0.1') d2 = decimal.Decimal('0.1') d3 = decimal.Decimal('0.1') print(d1 + d2 + d3) ``` > 在指定數字的時候,必須使用字串,但可以直接使用算術運算子做運算 如果對著布林值做運算,`True`會被當作1,`False`會被當作0,然後再進行運算,例如: ``` print(True+False) ``` 會輸出: ``` 1 ``` ##### 字串的運算 使用「+」可以用來串接運算,使用「*」可以重複字串,例如: ``` t1 = 'Hello' t2 = 'Aaron' print(t1 + t2) print(t1 * 5) ``` 會輸出: ``` HelloAaron HelloHelloHelloHelloHello ``` 字串因為本身不可以被修改,所以每次運算後都是產生新的字串。 Python本身偏向強型別,也就是不同型態之間在做運算時,比較不會進行自動轉換,所以字串和數字不能進行+運算,如果要進行串接,就必須先把數字轉成字串,如果要進行算數相加,就必須將字串先轉成數字,例如: ``` print('10' + str(3)) print(10 + int('3')) ``` 會輸出: ``` 103 13 ``` ##### `list、tuple運算` `list`使用「+」運算子可以進行串接,使用「*」,例如: ``` n1 = ['one', 'two'] n2 = ['three', 'four'] print(n1 + n2) print(n1 * 2) ``` 會輸出: ``` ['one', 'two', 'three', 'four'] ['one', 'two', 'one', 'two'] ``` 「+」和「*」運算在`tuple`上也有相同的效果,雖然`tuple`本身不能變動,但是當中的元素是可以變動的,例如: ``` n1 = [1, 2] n2 = [3, 4] nn = (n1, n2) print(nn) n1 = 5, 6 print(nn) ``` 會輸出: ``` ([1, 2], [3, 4]) ([5, 6], [3, 4]) ``` ##### 練習 1. 將: ``` a = [3, 4] b = [5, 6] ``` 轉換成: ``` [3, 4, 5, 6, 3, 4, 5, 6] ``` 並存放到result變數裡 2. 將: ``` c = [3.3, 6.6, 9.9] ``` 轉換成: ``` [9, 6, 3] ``` 並存放到result變數裡 ### 比較運算子 | 比較運算子 | 說明 | | ---------- | ------------------------------------------ | | > | 大於 | | >= | 大於或等於 | | < | 小於 | | <= | 小於或等於 | | == | 等於 | | != | 不等於 | | <> | 不等於(與!=功能相同)==Python 3已不支援== | > `<>`效果與`!=`相同,其只是為了相容性而存在,這裡列出只是為了將來見到不至於迷惘,請盡量使用`!=`來判斷,而不要使用`<>`,且在Python 3也已經不支援。 比較的結果,不是`Ture`就是`False`,代表成立或不成立。 > 請勿將`==`、`!=`與`is`、`is not`搞混,前者是比較物件真實的值,而後者是比較兩個物件的參考是否相同 ``` x = [2, 3] y = [2, 3] print(x == y) print(x is y) ``` 會輸出: ``` True False ``` 除了數字之外,字串、`list`、`set`、'tuple'和`dict`也都可以進行比較運算,其運算依從第一個元素依照順序做比較,而字元的比較為比較其字元碼(如英文字為ASCII碼),例如: ``` print('AAC' < 'ABC') print([2, 3] > [4, 5]) print((2, 3) == (4, 5)) print({2, 3} > {4, 5}) print({'A': 3} == {'A': 3) ``` 會輸出: ``` True False False False True ``` ### 指派運算子 除了目前已經用過的「=」指派運算子之外,其它的如下: | 指派運算子 | 範例 | 等同於 | | ---------- | ------- | ---------- | | += | a += b | a = a + b | | -+ | a -= b | a = a - b | | *= | a *= b | a = a * b | | /= | a /= b | a = a / b | | //= | a //= b | a = a // b | | %= | a %= b | a = a % b | | &= | a &= b | a = a & b | | \|= | a \|= b | a = a \| b | | ^= | a ^= b | a = a ^ b | | <<= | a <<= b | a = a << b | | >>= | a >>= b | a = a >> b | ### 邏輯運算子 | 邏輯運算子 | 說明 | | ---------- | ------------------------------------------------ | | and | 且,左右運算元都必須為真,其結果才為真,否則為假 | | or | 或,左右兩邊只要有一運算元為真,其結果即為真 | | not | 反相 | ``` print(True and True) print(True and False) print(True or False) print(not True) ``` 會輸出: ``` True False True False ``` 將`None、False、0、0.0、0j、''、()、[]、{}`等傳入`bool()`都會是`False`,其它值都會是`True`,這個原理也同樣套用在邏輯運算子上。 Python的邏輯運算子有捷徑運算的特性,也就是其運算的判斷由左至右,只要結果確立了,就會回傳確定結果位置的值。 `and`運算子左運算元如果為假,就可以確認邏輯不成立,因此可以不用繼續運算右運算元;`or`左運算元為真,則可以確定邏輯成立,因此可以不用運算右運算元,當判斷停留在哪裡,就會回傳該位置的運算元為結果值,例如: ``` print([] and 'Aaron') print([1, 2] and 'Aaron') print([] or 'Aaron') print([1, 2] or 'Aaron') ``` 會輸出: ``` [] Aaron Aaron [1, 2] ``` ### 位元運算子 | 位元運算子 | 說明 | | ---------- | ------------------------------------------ | | & | AND運算 | | \| | OR運算 | | ^ | 互斥OR運算 | | ~ | 補數運算 | | >> | 右移運算(左邊原來是0則補0,是1就補1) | | << | 左移運算(右邊會補上0) | 位元運算即是逐個位元做運算,例如: ``` print(0b10010001 & 0b01000001) print(0b10010001 | 0b01000001) print(~0b11) print(1 << 1) # 等同於2的1次方 print(1 << 3) # 等同於2的3次方 ``` 會輸出: ``` 1 209 -4 2 8 ``` 位元運算子除了數值的運算之外,還可以用在`set`上做交集(&)、聯集(|)、對稱差集(^)以及差集(-),並且可以用比較運算子(`>、<、>=、<=、==`)來比較兩個`set`的包括關係。 > **補充** > > 交集:只保留兩者皆有的元素,且只保留一份。 > > 聯集:兩者的元素合併,重複的元素只保留一份。 > > 對稱差集:兩者皆有的元素去掉,只保留兩邊互相沒有重複的元素。 > > 差集:前者有,但後者沒有的元素。 例如: ``` a = {1,2,3,4,5} b = {2,3,4,5,6} print(a & b) # 交集 print(a | b) # 聯集 print(a ^ b) # 互斥 print(a - b) # 差集 ``` 會輸出: ``` {2, 3, 4, 5} {1, 2, 3, 4, 5, 6} {1, 6} {1} ``` ### 索引切片運算 在Python中,只要具有索引特性的型態,基本上都可以使用切片(slice)運算,像是字串、list、tuple等等,透過切片運算,可以取得其內容之中的某一個片段,例如: ``` name = 'Aaron' print(name[0:3]) print(name[3:]) print(name[:2]) print(name[:]) print(name[:-1]) print(name[-3:-1]) ``` 輸出為: ``` Aar on Aa Aaron Aaro ro ``` 重點如下: 1. 其索引格式為:[start, end],start會包含其指定的索引值,但end指定的索引值不包含,索引從0開始代表第一個元素。 2. 如果是負數,表示從後面數,-1代表倒數第一個元素。 3. 如果冒號前面沒有指定,表示從頭開始,如果冒號後面沒有指定,表示最後一個元素。 切片運算另一個形式是:`[start:end:step]`,step代表每次間隔的內容,例如: ``` data = '1234567890' print(data[::2]) print(data[::-1]) ``` 會輸出: ``` 13579 0987654321 ``` 負數偏移表示以負偏移1的方式來取字串,結果就會變成反轉字串。