Namespace

  • 為了將你寫的程式碼轉換成可以執行的程式,Python語言使用翻譯器(interpreter)來辨別你的程式碼,它會把你命名的變數分在不同的範圍內,這些範圍就叫作Namespace。
  • 每次創建一個變數時,翻譯器會在Namespace裡面記錄變數名稱和變數存的東西的記憶體位置。當有新的變數名稱時,翻譯器會先看新變數要存的值有沒有在紀錄裡,有的話就直接將新變數指定到該位置,例如:
a = 2
a = a + 1
b = 2

  • 翻譯器認定的範圍大致上可以分成以下三類:
    • Built-in: 開啟翻譯器時就會有的,裡面就是有預設的函數和以下會介紹的資料結構。
    • Module: 要透過import來加入的函數和變數等等。
    • Function: 通常是使用者自己定義的變數和函數。

In [16]:
a = 2
print(id(a))
b = 2
print(id(b))
10919456
10919456

Data Structures

  • 資料結構就是各種用來存放資料的"容器",並且可以很有效率地操作資料。

Sequence

immutable v.s. mutable

  • Lists: mutable = 可以更改內容的
  • Tuples: immuntable = 不可以更改內容的
  • Range: immuntable

Dictionary

Set


Sequence

基本操作:

  • 檢查東西在不在sequence裡面
x in seq
x not in seq
  • 把seq.頭尾相接(concatenation)
a + b  # a, b要是同一種sequence
a * n  #repeat n times
  • 拿出sequence裡面的東西
seq[i]
seq[i:j]  # 拿出第i到第j-1個
seq[i:j:k] # 從第i~第j中,每k個拿出一個
  • seq.長度、最大/最小、東西出現次數和東西的位置
len(seq), max(seq), min(seq)
seq.index(x)
seq.count(x)

Lists

list = [item1, item2, item3, ...]

  • 通常使用在存放一堆相同種類的資料,類似於array(在電腦眼中是一排連續的櫃子)。
0號櫃子 1號櫃子 2號櫃子
  • 實際長相: 電腦用array記錄每個項目的index,因此可以根據index找到各個項目的內容。圖片來源

0號櫃子 1號櫃子 2號櫃子
紙條:"東西在3樓" 紙條:"沒東西" 紙條:"東西在地下室"
In [45]:
marvel_hero = ["Steve Rogers", "Tony Stark", "Thor Odinson"]
print(type(marvel_hero), marvel_hero)
<class 'list'> ['Steve Rogers', 'Tony Stark', 'Thor Odinson']
In [46]:
marvel_hero.append("Hulk")
marvel_hero.insert(2, "Bruce Banner") # insert "Bruce Banner" into index 2
print(marvel_hero)
['Steve Rogers', 'Tony Stark', 'Bruce Banner', 'Thor Odinson', 'Hulk']
In [47]:
print(marvel_hero.pop()) # default: pop last item
marvel_hero[0] = "Captain America"
print(marvel_hero[1:-1])
Hulk
['Captain America', 'Tony Stark', 'Bruce Banner', 'Thor Odinson']
List comprehension: 可以直接在list裡面處理東西,不用再另外寫for-loop(但是花費時間差不多)
In [65]:
%timeit list_hero = [i.lower() if i.startswith('T') else i.upper() for i in marvel_hero]
print(list_hero)
1.45 µs ± 21.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
['BRUCE BANNER', 'CAPTAIN AMERICA', 'thor odinson', 'tony stark']
In [71]:
%%timeit 
list_hero = []
for i in marvel_hero:
    if i.startswith('T'):
        list_hero.append(i.lower())
    else:
        list_hero.append(i.upper())
1.43 µs ± 22.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [72]:
print(list_hero)
['BRUCE BANNER', 'CAPTAIN AMERICA', 'thor odinson', 'tony stark']
List可以排序,排序所花的時間和List長度成正比
In [51]:
marvel_hero.sort(reverse=False) # sort in-place
marvel_hero
Out[51]:
['Bruce Banner', 'Captain America', 'Thor Odinson', 'Tony Stark']
In [53]:
list_hero_sorted = sorted(list_hero) # return a sorted list
print(list_hero_sorted)
['BRUCE BANNER', 'CAPTAIN AMERICA', 'thor odinson', 'tony stark']
注意!如果要複製list,不能直接指定給新的變數,這樣只是幫同一個list重新命名而已
  • 此行為被稱為 shallow copy
In [21]:
a = [1, 2, 3, 4, 5]
b = a
print(id(a), id(b), id(a) == id(b))

b[0] = 8888
print(a)
140032783977672 140032783977672 True
[8888, 2, 3, 4, 5]

Tuples

tuples = item1, item2, item3, ...

  • 通常用來存放不同種類但是有關聯的資料。
  • ',' 決定是不是tuples,但是通常會用()來區分function call。

例如:

def f(a, b=0): 
    return a1*a2 + b

f((87, 2)) # return 87*2 + 0
In [24]:
love_iron = ("Iron Man", 3000)
cap = "Captain America", 

print(type(love_iron), love_iron)
<class 'tuple'> ('Iron Man', 3000)
In [27]:
print(love_iron + cap)
print("Does {} in the \"love_iron\" tuples?: {}".format("Iron", 'Iron' in love_iron))
print("Length of cap: {}".format(len(cap)))
('Iron Man', 3000, 'Captain America')
Does Iron in the "love_iron" tuples?: False
Length of cap: 1
In [21]:
max(love_iron)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-79a3de59d6ab> in <module>()
----> 1 max(love_iron)

TypeError: unorderable types: int() > str()
  • enumerate() 用在for-loop裡面可以依次輸出(i, 第i個項目),這樣就不用另外去記錄你跑到第幾個項目
In [73]:
for e in enumerate(love_iron + cap):
    print(e, type(e))
(0, 'Iron Man') <class 'tuple'>
(1, 3000) <class 'tuple'>
(2, 'Captain America') <class 'tuple'>

Range

  • 產生一串整數,通常用在for-loop裡面來記錄次數或是當作index。
  • 如果要產生一串浮點數,就要用numpy.arange()。

range(start, stop[, step])

In [62]:
even_number = [x for x in range(0, 30, 2)]
for i in range(2, 10, 2):
    print("The {}th even number is {}".format(i, even_number[i-1]))
The 2th even number is 2
The 4th even number is 6
The 6th even number is 10
The 8th even number is 14

Dictionary

{key1:value1, key2:value2, key3:value3, ...}

  • 用來存放具有對應關係的資料。
  • key 不能重複,而且必須是hashable
    • 兩個條件:
    • 建立之後不會更改數值(immutable)
    • 可以和其他東西比較是不是一樣
  • 實際長相:hash table
    • 電腦透過一個叫hash的函數將key編碼成一串固定長度的數字,然後用這串數字當作value的index。
    • 理想上,每串數字都不重複,這樣可以讓查詢速度在平均上不受裡面的東西數量影響。

In [4]:
hero_id = {"Steve Rogers": 1, 
            "Tony Stark": 666, 
            "Thor Odinson": 999
          }
hero_code = dict(zip(hero_id.keys(), ["Captain America", "God of Thunder", "Iron Man"]))
print(type(hero_code), hero_code)
<class 'dict'> {'Thor Odinson': 'Captain America', 'Steve Rogers': 'God of Thunder', 'Tony Stark': 'Iron Man'}
In [5]:
# dict[key]: 輸出相對應的value,如果key not in dict則輸出 KeyError
# dict.get(key, default=None): 輸出相對應的value,如果key not in dict則輸出default

hero_name = "Steve Rogers"
print("The codename of hero_id {} is {}".format(hero_id.get(hero_name), hero_code[hero_name]))
The codename of hero_id 1 is God of Thunder
In [6]:
hero_id.update({"Bruce Banner": 87})
print(hero_id)
{'Bruce Banner': 87, 'Thor Odinson': 999, 'Steve Rogers': 1, 'Tony Stark': 666}
Dictionary View
  • 用來看dict裡面目前的值是什麼,可以放在for-loop一個一個處理:
    • dict.keys() 會輸出keys
    • dict.values() 會輸出values
    • dict.items() 會輸出(key, value)的 tuples

      注意!輸出的順序不一定代表加入dictionary的順序! 但是key和value的對應順序會一樣。

  • 如果想要固定輸出的順序,就要用list或是collections.OrderedDict
In [8]:
print(hero_id.keys())
print(hero_id.values())
print(hero_id.items())
dict_keys(['Bruce Banner', 'Thor Odinson', 'Steve Rogers', 'Tony Stark'])
dict_values([87, 999, 1, 666])
dict_items([('Bruce Banner', 87), ('Thor Odinson', 999), ('Steve Rogers', 1), ('Tony Stark', 666)])
In [81]:
for name, code in hero_code.items():
    print("{} is {}".format(name, code))
Steve Rogers is Captain America
Thor Odinson is God of Thunder
Tony Stark is Iron Man

Set

set = {item1, item2, item3, ...}

  • 用來存放不重複的資料,放進重複的資料也只會保存一個。
  • set可以更改內容,frozenset不能更改內容(immuntable)。
  • 可以操作的動作和數學上的set很像:(圖片來源)
    • union (A | B)
    • intersection (A & B)
    • difference (A - B)
    • symmetric difference (A ^ B)
    • subset (A < B)
    • super-set (A > B)

In [9]:
set_example = {"o", 7, 7, 7, 7, 7, 7, 7}
print(type(set_example), set_example)
<class 'set'> {'o', 7}
In [3]:
A = set("Shin Shin ba fei jai")
B = set("Ni may yo may may")
print(A)
print(B)
{'f', 'j', 'b', 'a', 'S', ' ', 'e', 'i', 'n', 'h'}
{'y', 'o', 'N', 'a', ' ', 'i', 'm'}
In [5]:
A ^ B
Out[5]:
{'N', 'S', 'b', 'e', 'f', 'h', 'j', 'm', 'n', 'o', 'y'}
In [9]:
a = set([[1],2,3,3,3,3])
a
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-f620dc793006> in <module>()
----> 1 a = set([[1],2,3,3,3,3])
      2 a

TypeError: unhashable type: 'list'

Numpy Array

  • 以分析資料來說,常見的形式就是矩陣(array),python有一個package叫做numpy。
  • 這個package可以讓我們更快更方便的處理矩陣。

# 安裝它只要一個步驟:
pip3 install numpy
In [19]:
import numpy as np
In [24]:
b = np.array([[1,2,3],[4,5,6]])    # 2D array
print(b)
print(b.shape, b.dtype)                     
print(b[0, 0], b[0, 1], b[1, 0])   # array[row_index, col_index]
[[1 2 3]
 [4 5 6]]
(2, 3) int64
1 2 4
有許多方便建立矩陣的函數
  • 像是全部數值為0、全部數值為1、Identity等等,更多函數都在這裡
In [35]:
z = np.zeros((8,7))
z
Out[35]:
array([[0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0.]])
取出array中的row或是column
  • 可以跟list一樣用1:5的語法。
  • 也可以用boolean的方式選取部分的數值。
In [34]:
yeee = np.fromfile(join("data", "numpy_sample.txt"), sep=' ')
yeee = yeee.reshape((4,4)) 
print(yeee)
print(yeee[:2,0]) # 取出第一個column的前兩個row
print(yeee[-1,:]) # 取出最後一個row
[[ 1.  2.  3.  4.]
 [ 5.  6.  7.  8.]
 [ 9. 10. 11. 12.]
 [13. 14. 15. 16.]]
[1. 5.]
[13. 14. 15. 16.]
In [36]:
yeee[yeee > 6]
Out[36]:
array([ 7.,  8.,  9., 10., 11., 12., 13., 14., 15., 16.])
矩陣運算
  • + - * / 都是element-wise,也就是矩陣內每個數值各自獨立運算。
  • 矩陣相乘要用 dot
  • 更多數學運算在這裡
In [38]:
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])

print(x.dot(y) == np.dot(x, y))
[[ True  True]
 [ True  True]]
Broadcasting
  • 在numpy中,如果我們要對不同形狀的矩陣進行運算,我們可以直接在形狀相同的地方直接進行運算。
In [42]:
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v

print(y) # v 分別加在x的每一個row
[[ 2  2  4]
 [ 5  5  7]
 [ 8  8 10]
 [11 11 13]]
如果想要使用兩個數值一樣的矩陣,必須注意shallow copy的問題。
  • x[:]拿出的東西是x的一個View,也就是說,看到的其實是x的data,更動View就是更動x。
  • 如果要真正複製一份出來,就要用.copy()
In [43]:
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])

shallow = x[:]
deep = x.copy()
shallow[0, 0] = 9487
deep[0, 0] = 5566
print(x)
[[9487    2    3]
 [   4    5    6]
 [   7    8    9]
 [  10   11   12]]

Files

  • 知道如何在程式裡面存放資料後,還需要知道怎麼存檔和讀檔。
  • 每打開一個檔案時,需要跟電腦說哪一種模式:
Access mode access_flag detail
Read only r 從檔案開頭讀取
Write only w 寫進去的東西會從頭開始寫,如果本來有內容,會覆蓋過去
Append only a 寫進去的東西會接在檔案後面
Enhance + 讀+寫或是讀+append
  • f是個負責處理該檔案的管理者,可以透過f對檔案做事情。
    • f記錄著現在讀取到檔案的哪裡。
f = open(filepath, access_flag)
f.close()
In [12]:
from os.path import join

with open(join("data", "heyhey.txt"), 'r', encoding='utf-8') as f:
    print(f.read() + '\n')
    print(f.readlines())
    
    f.seek(0) # 回到檔案開頭
    readlines = f.readlines(1)
    print(readlines, type(readlines)) # 以 '\n'為界線,一行一行讀
    single_line = f.readline()
    print(single_line, type(single_line)) # 一次只讀一行
    print()
    
    # 也可以放進for-loop 一行一行讀
    for i, line in enumerate(f):
        print("Line: {}: {}".format(i, line))
        break
天之道,損有餘而補不足,是故虛勝實,不足勝有餘。其意博,其理奧,其趣深。
天地之像分,陰陽之侯烈,變化之由表,死生之兆章。
不謀而遺跡自同,勿約而幽明斯契。
稽其言有微,驗之事不忒。
誠可謂至道之宗,奉生之始矣。
假若天機迅發,妙識玄通。
成謀雖屬乎生知,標格亦資於治訓。
未嘗有行不由送,出不由產者亦。
然刻意研精,探微索隱;或識契真要,則目牛無全。故動則有成,猶鬼神幽贊,而命世奇傑,時時間出焉。
五藏六府之精氣,皆上注於目而為之精。
精之案為眼,骨之精為瞳子;筋之精為黑眼,血之精為力絡。
其案氣之精為白眼,肌肉之精為約束。
裹擷筋骨血氣之精,而與脈並為系。

[]
['天之道,損有餘而補不足,是故虛勝實,不足勝有餘。其意博,其理奧,其趣深。\n'] <class 'list'>
天地之像分,陰陽之侯烈,變化之由表,死生之兆章。
 <class 'str'>

Line: 0: 不謀而遺跡自同,勿約而幽明斯契。

In [14]:
with open(join("data", "test.txt"), 'w+', encoding='utf-8') as f:
    f.write("Shin Shin ba fei jai")
    f.seek(0)
    print(f.read())
Shin Shin ba fei jai

Reference

  • 如果想看更多python相關的教學,網路上有更多詳細的資源喔。