<style>
.alert-info {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
}
</style>
書接上回
先前介紹了Python這門語言的基本安裝和套件管理器
這次就要開始進入Python的語法和基本特性了
# 前言
Python是一門在資料科學和Pwn中常用到的語言
廣受歡迎的理由不外乎是寫起來很方便
雖然是強型別
但簡單的語法和規則讓其受到眾人的喜愛
今天我們就從基本的資料型態和資料結構開始吧
# 觀前提示
- 本篇文章將主要以CLI方式進行 若有使用上的需求可以參考CLI工作訣竅
- 本文適用於主流的MacOS、Linux、Windows系統
- 本文將以Python3.12為案例進行說明 若需求不同請自行調整
- 請務必知道你自己在做什麼 希望你不要把電腦搞壞
- 本系列預設你會寫程式 只是要學新語言
# 主文
# 確認Python環境
先前我們安裝過Python了
首先我可以先在終端裡輸入
python3 --version
看看我們的python版本
確認版本無誤後
接著我們可以輸入
python3
此時會看到畫面進入一坨奇怪的輸入
一些版權聲明還有版本資訊
以及一個>>>的符號出現
❯ python3
Python 3.12.1 (main, Feb 27 2024, 14:28:09) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
進到這裡就跟終端一樣可以輸入python語法作為指令
這裡我們試試看程式人都應該第一個學的最基本的輸出語法
print("Hello, World!")
# Hello, World!
看來一切就緒了
那我們可以準備開始進入編寫一個python檔案了了
# 建立專案
在編寫程式之前
開一個空白的資料夾
存放我們的專案和程式碼
我們也可以使用之前提過的poetry進行專案的初始化和套件管理
不過這裡我們先以基本的純腳本為主
mkdir python_project
cd python_project
touch main.py
迷之音:為什麼不要右鍵創建新檔案呢
接著使用編輯器打開main.py
就可以開始寫程式了
# 基本IO
寫程式最大的目標
正是將使用者的輸入
透過運算和邏輯判別後
輸出給使用者看到回饋
寫Python也不外乎如此
a = input()
print(a)
接著在終端機打上python3 main.py(或者你有裝任何套件可以幫你點一下就執行)
就能夠執行這份檔案了
緊接著隨便輸入點東西按下enter
可以看到系統回吐給你了一份一樣的東西
這樣就有一份基本的IO足以入門了
嗯 你說太快了 不知道在幹嘛?
我們簡單解釋一下我們剛剛做了什麼
首先 input()是一個python自帶的函數
能夠從標準輸出入中讀取字串並且回傳出來
此時 我們將其丟入到一個暫存的a中
再使用print()這個函數
將a這個變數的內容印出來
或許有點複雜
但這就是一個最基本的IO操作了
我們這裡只先解釋作用
之後再來解釋實際的原理
# Python的變數
前一小節中我們提到
我們將input()的內容存進了一個變數a中
# 變數的邏輯
那麼 在python中變數是怎樣的概念呢
可以想像的是
變數就是一個盒子
我們可以將一些想存放的東西放進去
需要時再取出來使用
實際上運作的原理就是程式在記憶體中先預支一個空位
接著將我們的資料存放進去
之後等要用到 再去呼叫該位址進而獲得我們需要的值
# 變數的型別
變數這種資料的容器
想當然 必須有一些規定和限制
不然每個人都把超級大胖子丟進狹小空間還得了
在python中
常見的基本型別有三種
分別是int(整數)、float(浮點數)、str(字串)
聽名字大概知道
如果我們要存年齡或人數 那我們可以選用int
如果我們要存身高或體重 那我們可以選用float
如果我們要存名字或者一段文字 那我們可以選用str
值得注意的是 在Python中字元也是直接以字串的形式引用的喔
# 變數的型別 之 為什麼要規定
如果有學過其他強型別語言
尤其是C#、Java等類型語言的話
應該會注意到一件事情
在其他語言中
定義變數時的樣子是這樣
int a = 1;
string b = "Hello, World!";
然而 在我們之前的範例中
在宣告變數時並沒有去定義前面的型別
這是因為
Python雖然也是強型別語言
但是它是一門動態語言
因此 當程式底層在執行的時候
會自動將我們的變數進行型別的判斷
所以我們在宣告變數時並不需要特別去指定型別
只需要將
變數名字 = 值
即可完成變數的宣告
# 變數的命名和型別提示
雖然在Python中 變數的命名並沒有硬性規定
但多數人 起碼筆者我自己使用底線法
也就是_來分隔變數名稱
而不是採用駝峰式的命名(公開class除外)
並且 雖然我們不需要在宣告變數時定義其型態
我們依舊可以可以在變數名字後面
加上型別提示 以便我們之後這個變數是什麼型態避免混亂
a: int = 1
b: str = "Hello, World!"
這樣的命名方式可以讓可讀性更高喔
# python中的註解
有時候 變數在宣告後
如果名字寫得不夠精確
或者寫了也不是很懂他的用途
這時候我們可以使用註解的方式去補充說明
在Python中
註解分為兩種
一種是單行的註解 而另一種是多行的註解
使用方式很簡單
# 這是一個單行註解
"""
這是多行註解
"""
根據自己的狀況使用
有助於幫助自己在後續維護的方便喔
# Python的資料結構
在大學學習程式時
有一門課叫做資料結構
其目的正式要用程式原生的資料格式 利用邏輯進行一定的組合後
實作出一個能夠更有效率的存放資料的容器
然而 在Python中
有許多的資料結構是內建的
# List
這或許是整個Python最外掛的結構了
List是一個能夠存放多個元素的容器
可以存放任何型態的資料
並且同時擁有增刪改查的功能
# 建立一個list
my_list = [1, 2, 3, "hello", True]
# 取值(index從0開始)
print(my_list[0]) # 1
print(my_list[-1]) # True(從尾巴算回來)
# 切片(slicing)
print(my_list[1:3]) # [2, 3]
常用的操作方法
fruits = ["apple", "banana"]
# 新增
fruits.append("cherry") # 尾巴加一個 -> ["apple", "banana", "cherry"]
fruits.insert(1, "orange") # 指定位置插入 -> ["apple", "orange", "banana", "cherry"]
# 刪除
fruits.remove("banana") # 刪除指定元素
fruits.pop() # 刪除最後一個並回傳
fruits.pop(0) # 刪除指定index並回傳
# 查詢
print(len(fruits)) # 長度
print("apple" in fruits) # 是否存在(回傳bool)
print(fruits.index("apple")) # 取得index
# 排序
numbers = [3, 1, 4, 1, 5, 9]
numbers.sort() # 原地排序
sorted_nums = sorted(numbers) # 回傳新的排序結果(不改變原本的)
List是可以被修改(mutable)的 這點很重要 後面會跟Tuple做比較
# Tuple
Tuple長得跟List很像
差別在於Tuple是不可修改(immutable)的
# 建立一個tuple
my_tuple = (1, 2, 3, "hello")
# 取值跟list一樣
print(my_tuple[0]) # 1
print(my_tuple[1:3]) # (2, 3)
# 但你不能改它
my_tuple[0] = 99 # TypeError: 'tuple' object does not support item assignment
你可能會問 那這東西到底有什麼用
既然不能改 為什麼不全部用List就好
答案是安全性和效能
Tuple因為不可修改 所以可以當作dict的key(後面會講)
而且在大量資料的情境下 Tuple的存取效能比List要好
如果你有一組資料確定不會被改動(例如座標、RGB值之類的)
用Tuple比List更合適
# 常見的使用場景
coordinate = (25.0, 121.5)
rgb_color = (255, 128, 0)
# 可以用來做多值回傳
def get_user():
return ("Miyago", 24)
name, age = get_user() # 解包(unpacking)
# Dict
Dict全名Dictionary 字典
是一個用key-value配對來存放資料的結構
如果你學過其他語言 它就是Map或HashMap
# 建立一個dict
user = {
"name": "Miyago",
"age": 24,
"job": "SRE"
}
# 取值
print(user["name"]) # Miyago
print(user.get("email")) # None(用get不會報錯)
print(user.get("email", "N/A")) # N/A(找不到時的預設值)
# 新增或修改
user["email"] = "miyago@example.com"
user["age"] = 25
# 刪除
del user["email"]
user.pop("job") # 刪除並回傳值
常用操作
user = {"name": "Miyago", "age": 24, "job": "SRE"}
# 遍歷
for key in user:
print(key, user[key])
for key, value in user.items():
print(key, value)
# 取得所有key和value
print(user.keys()) # dict_keys(['name', 'age', 'job'])
print(user.values()) # dict_values(['Miyago', 24, 'SRE'])
# 合併(Python 3.9+)
extra = {"city": "Taipei", "lang": "Python"}
merged = user | extra
Dict的key必須是immutable的型態
所以str、int、tuple可以當key
但list不行 因為list是mutable的
這也是為什麼Tuple有其存在意義的原因之一
# Set
Set是一個無序且不重複的集合
如果你只在乎「有沒有」而不在乎「在哪裡」或「有幾個」
Set就是你最好的朋友
# 建立一個set
my_set = {1, 2, 3, 3, 3}
print(my_set) # {1, 2, 3} 重複的自動去掉
# 新增和刪除
my_set.add(4)
my_set.remove(1) # 如果不存在會報錯
my_set.discard(99) # 如果不存在也不會報錯
# 檢查是否存在
print(3 in my_set) # True
Set最強大的地方在於集合運算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a & b) # {3, 4} 交集
print(a | b) # {1,2,3,4,5,6} 聯集
print(a - b) # {1, 2} 差集
print(a ^ b) # {1, 2, 5, 6} 對稱差集
最常見的用途就是去重
names = ["Miyago", "Alice", "Bob", "Miyago", "Alice"]
unique_names = list(set(names))
print(unique_names) # ['Bob', 'Alice', 'Miyago'](順序不保證)
# 型態之間的比較
最後做一個簡單的整理
| 結構 | 有序 | 可修改 | 可重複 | 取值方式 |
|---|---|---|---|---|
| List | O | O | O | index |
| Tuple | O | X | O | index |
| Dict | X(3.7+有序) | O | key不可重複 | key |
| Set | X | O | X | 無(只能檢查存在) |
嚴格來說 Python 3.7之後Dict是insertion-ordered的
也就是你放進去的順序會被保留
但邏輯上還是不要依賴這個特性比較好
# 結語
以上就是Python中最基本的資料型態和資料結構了
雖然看起來東西不少
但實際上最常用的就是list和dict
把這兩個搞熟了基本上就能應付大部分的場景
下一篇預計會講到流程控制(if/for/while)和函數
也就是真正開始寫邏輯的部分了
那我們就下篇見吧
