Python Getting Started
- :thumbsup: 為你自己學 PYTHON
- Complete-Python-3-Bootcamp @ GitHub
# 在 REPL 環境下載入某支檔案
$ python -i hello.py
Setup & Installation
PIP
- PIP
- Version Specifiers:安裝特定版本的套件
$ pip list # 檢視目前電腦上安裝哪些 python package
$ pip install [package] # 安裝套件
$ pip uninstall [package] # 移除套件
$ pip show [package] # 檢視套件資訊
venv
# 建立 virtual env
$ python -m venv [virtual_environment_name]
$ python -m venv .venv # 建立名為 .venv 的 virtual environment
# 啟動 virtual env
$ source [virtual_environment_name]/bin/activate
# 進入 virtual env 後,使用 deactivate 可以離開
> deactivate
# 把目前專案有安裝的套件寫進 requirement.txt 中
$ pip freeze > requirements.txt
# 安裝 requirement.txt 中列出的套件
$ pip install -r requirements.txt
Poetry
參考:[note] Python Poetry @ PJCHENder
VSCode
Getting Started with Python in VS Code @ Youtube
Data Structure Basic
Variable
a = 3
type(a) # int
String
##
# Index and Slice
##
'tinker'[1:4] # 'ink'
'tinker'[1:4:2] # 'ik'
'tinker'[::-1] # 'reknit
##
# Formatting with the .format() method
##
'Good {}, {} Chen!'.format('morning', 'Mr.') # 'Good morning, Mr. Chen!'
'My favorite brand is {}, {}, and {}!'.format('Apple', 'Samsung', 'Google') # 'My favorite brand is Apple, Samsung, and Google!'
'My favorite brand is {2}, {1}, and {0}!'.format('Apple', 'Samsung', 'Google') # 'My favorite brand is Google, Samsung, and Apple!'
'Repeat after me: {0}! {0}! {0}!'.format('Ho') # 'Repeat after me: Ho! Ho! Ho!'
'Good {time}, {title} {name}!'.format(time='morning', title='Mr.', name='Chen') # 'Good morning, Mr. Chen!'
##
# Float Formatting
##
result = 100/777 # 0.1287001287001287
# Old Way, {value:width.precision f}
print("The result was {:1.3f}".format(result)) # The result was 0.129
# Formatted String Literals(f-strings)
name = 'Aaron'
age = 33
print(f'Hello, my name is {name}, and I\'m {age} years old.')
List
[0]*3 # [0, 0, 0]
my_list = [1, 3, 2]
another_list = [4, 6, 5]
# array concat
whole_list = my_list + another_list
whole_list # [1, 3, 2, 4, 6, 5]
# sort
whole_list.sort()
whole_list # [1, 2, 3, 4, 5, 6]
whole_list.reverse()
whole_list # [6, 5, 4, 3, 2, 1]
Dict
Mapping Types - Dict @ Python Doc > Built-in Type
Dictionary 基本操作
建立 Dictionary
user1 = {'name': 'John', 'age': 25}
user2 = dict(name='John', age=25)
user_from_tuple = (('name', 'John'), ('age', 25))
user3 = dict(user_from_tuple)
user_from_list = [['name', 'John'], ['age', 25]]
user4 = dict(user_from_list)
dictionary 的 key 必須要是 hashable,因此可以是 string、number、bool、tuple。
在 Dictionary 中新增或更新 Key-Value
# 使用 []
user = {'name': 'John', 'age': 25}
user["height"] = 180
# 使用 update,如果存在就更新,不存在就新增
user.update({
"height": 180,
"width": 76
})
# 使用 unpacking operator
new_user = {
**user,
"height": 180,
"width": 76
}
# 使用 |
user = {'name': 'John', 'age': 25}
info = {"height": 180, "width": 76}
new_user = user | info
取值
user = {'name': 'John', 'age': 25}
user["name"] # "John"
user["foo"] # KeyError: 'foo'
# 使用 get:如果沒有該 key 不會噴錯
# get(key, default=None)
user.get("foo") # None
user.get("foo", "default_value") # default_value
刪除 key
user = {'name': 'John', 'age': 25}
del user["name"] # 刪除 name 這個 key-value pair
user.clear() # 把 user 中的 key-value pairs 清空,變成 empty dictionary
pop, popitem:把 key-value pair 中 dictionary 中取出(後刪除)
user = {'name': 'John', 'age': 25}
user_name = user.pop("name") # "John",並把 user 中的 {"name": "John"} 移除
user_age = user.pop("age", 30) # 25, 如果沒有 age 這個 key,則用 default value(30)
user = {'name': 'John', 'age': 25}
age_info = user.popitem() # ('age', 25),把最後一組 key-value pair 拿出來
複製 dictionary
user = {'name': 'John', 'age': 25}
# 使用 copy
new_user = user.copy()
# 使用 dict
new_user = dict(user)
# 使用 unpacking operator
new_user = {**user}
常用方法
Dict Comprehensions
names = ['Jenny', 'Aaron', 'Sam', 'Grace']
ages = [23, 25, 20, 27]
participants = {k:v for k, v in zip(names, ages)} # {'Jenny': 23, 'Aaron': 25, 'Sam': 20, 'Grace': 27}
dict.fromkeys():從其他 iterable object 建立 dictionary
# 根據字串、串列或 Tuple 來建立 Dict 的 key
# classmethod fromkeys(iterable, value=None, /)
dict.fromkeys(['name', 'age'])
dict.fromkeys(['name', 'age'], '') # {'name': '', 'age': ''}
in:判斷 dictionary 中是否有該 key
user = {'name': 'John', 'age': 25}
"name" in user # true
unpacking operator (**):可以用來合併 dictionary
defaults = {'color': 'red', 'size': 'medium', 'price': 100}
updates = {'color': 'blue', 'price': 150}
final = {**defaults, **updates} # {'color': 'blue', 'size': 'medium', 'price': 150}
迭代 dictionary
user = {'name': 'John', 'age': 25}
len(user) # 2
# 直接迭代 dictionary 會拿到 key
for key in user:
print(k)
# 取得所有 keys
user.keys() # dict_keys(['name', 'age'])
list(user) # ["name", "age"]
user.values() # dict_values(['John', 25])
list(user.values()) # ['John', 25]
for value in user.values():
print(value)
user.items() # dict_items([('name', 'John'), ('age', 25)])
list(user.items()) # [('name', 'John'), ('age', 25)]
for k, v in user.items():
print(f"{k}: {v}")
要特別留意的是,使用 keys()
、values()
、或 items()
拿到的資料並不是真的帶有 key、value 的 list,而是一個「view」讓我們可以透過它看到目前 dictionary 的資料。因此即使把它存成變數,一旦原本的 dictionary 改變,這個變數得到的內容也會改變。
Tuple
基本操作
建立 Tuple
# 使用 ()
single = (1,)
mixed = (1, "hello", True)
empty = ()
# 使用 tuple constructor
list_to_tuple = tuple([1, 2, 3]) # (1, 2, 3)
string_to_tuple = tuple("hello") # ('h', 'e', 'l', 'l', 'o')
range_to_tuple = tuple(range(3)) # (0, 1, 2)
Operators
Comparisons Operators
1 < 2 < 3 # True
1 < 2 and 2 < 3 # True
1 == 1 or 2 == 2 # True
not ( 1 == 1 ) # False
not ( 400 > 5000 ) # True
Useful Operators
range(start, stop, step)
# 0, 1, 2
for i in range(3):
print(i)
# 3, 4
for i in range(3,5):
print(i)
# 1,3,5
for i in range(1,6,2):
print(i)
# [0, 2, 4]
list(range(0, 5, 2))
enumerator
把 string 變成 tuple
word = 'abc'
# 0: a
# 1: b
# 2: c
for idx, value in enumerate(word):
print(f'{idx}: {value}')
zip
把多個 list 組成一個 tuple
name = ['Aaron', 'John', 'Mary']
age = [12, 13, 14]
height = [170, 180, 160]
# Aaron is 12 years old with 170 cm
# John is 13 years old with 180 cm
# Mary is 14 years old with 160 cm
for name, age, height in zip(name, age, height):
print(f'{name} is {age} years old with {height} cm')
# <zip object at 0x1023a1300>
zip(name, age, height)
# [('Aaron', 12, 170), ('John', 13, 180), ('Mary', 14, 160)]
list(zip(name, age, height))
in
1 in [1, 2, 3] # True
'a' in 'abc' # True
'a' in [1, 2, 3] # False
user = {
"name": "John",
"age": 30,
"city": "New York"
}
'name' in user # True
'John' in user.values()
Statements
Conditional Statements
state = 'active'
if state == 'active':
print('The state is active')
elif state == 'inactive':
print('The state is inactive')
else:
print('The state is unknown')
For Loops
Iterate a list
brands = ['Ford', 'BMW', 'Volvo']
for brand in brands:
print(brand)
Combine with conditional statement:
brands = ['Ford', 'BMW', 'Volvo']
for brand in brands:
if brand == 'Volvo':
print(brand + ' - I like it!')
else:
print(brand + ' - I don\'t like it!')
Iterate a string
str = 'Hello World'
for letter in str:
print(letter)
Iterate a tuple
for t in (1, 2, 3):
print(t)
Tuple Unpacking
my_list = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
for a, b in my_list:
print(a + b)
Iterate an dictionary
user = {
"name": "John",
"age": 30,
"city": "New York"
}
for key in user:
print(f'key: {key}')
print(f'value: {user[key]}')
for key, value in user.items():
print(f'key: {key}')
print(f'value: {value}')
for value in user.values():
print(value)
While Loops
x = 0
while x < 5:
# x = x + 1
x += 1
print(f'The current value of x is {x}')
# could combine with "else"
else:
print('X IS NOT LESS THAN 5')
Basic I/O
Read and Write files
mode='r'
: read onlymode='w'
: write only (will overwrite existing files or create new)mode='a'
: append onlymode='r+'
: read and writemode='w+'
: write and read (overwrite existing files or create new)
myfile = open('myfile.txt')
myfile.read()
myfile.seek(0) # reset cursor
myfile.readlines() # returns a list of lines
myfile.close() # close file
# 不用怕忘記 close 的寫法
# create or overwrite a file
with open('myfile.txt', mode="w") as my_new_file:
contents = my_new_file.write(
'this is a text file\nthis is the second line\nthis is the third line')
# read file
with open('myfile.txt', mode='r') as f:
contents = f.read()
print(contents)
# append file
with open('myfile.txt', mode='a') as f:
f.write('\nthis is the fourth line')
with open('myfile.txt', mode='r') as f:
contents = f.read()
print(contents)
Modules and Packages(模組與套件)
定義 Modules 和 Packages
- Module(模組)指的就是
.py
「檔案」,在 Python 中不需定義要 export 哪些變數,可以自由 import - Package(套件)則是一個包含許多 modules 的「資料夾」,要變成 package,只需要把檔案(模組)整理在資料夾中,並在資料夾中加上
__init__.py
的檔案(在 Python 3.2 之後可以不用加這隻檔案亦可) - 一個 Package 中還可以有 sub package,只要在該資料夾中同樣加上
__init__.py
的即可。
舉例來說,我們的資料結構如下:
.
├── main_package
│ ├── __init__.py
│ ├── main_module.py # 裡面有定義 report_main_method()
│ └── sub_package
│ ├── __init__.py
│ └── sub_module.py # 裡面有定義 report_sub_method()
├── my_module.py # 裡面有定義 my_function()
└── main.py
如果想要在 main
中使用 my_module
模組中的 report_my_method
方法:
"""
可以直接匯入「整個模組」
"""
import my_module
my_module.report_my_method()
"""
也可以「匯入模組中」的「部分方法」
"""
from my_module import report_my_method
report_my_method()
如果想要在 main
中使用 main_package
套件的 main_module
模組裡 report_main_method
方法,可以這樣匯入:
"""
可以匯入「整個套件」
"""
import main_package
main_package.main_module.report_main_method()
"""
可以匯入「套件中」的「部分模組」
"""
from main_package import main_module
main_module.report_main_method()
"""
也可以匯入套件中的整個「模組」
"""
import main_package.main_module
main_package.main_module.report_main_method()
"""
也可以「匯入模組中」的「部分方法」
"""
from main_package.main_module import report_main_method
report_main_method()
和 sub_package
中的方法,只需要這樣 import 即可
# package 則是 folder name
from main_package import main_script
main_script.report_main()
from main_package.sub_package import sub_script
my_function()
sub_script.report_sub_script()
- 匯入的模組也是物件,可以使用
dir(my_module)
來檢視這個模組中有哪些方法可以使用 - 被匯入的模組(這隻檔案)會被 Python 執行,即使只匯入部分方法也是
- 使用
sys.path
可以查看 Python 搜尋模組的路徑 - 使用
sys.modules
可以查看哪些模組被匯入
如果要判斷某個檔案是不是直接被執行,而不是透過 import 的方式被載入後才執行,可以使用 __name__ == "__main__"
,當這個檔案是直接被執行時,會得到 true
,否則,它會是模組的名稱。
如果有需要的話,也可以使用 as
(alias)來替import 的 module 改名字:
import numpy as np
from matplotlib.pyplot import plot as plt
np.array([1, 2, 3])
plt([1, 2, 3], [4, 5, 6])
明確定義其他人 import module 的方式
因為 module 中的所有變數、方法都可以被 import,所以如果我們希望明確定義哪些是「希望」開放給其他人使用的 module 時,可以搭配 as
定義在 __init__.py
中。例如:
# fastapi/__init__.py
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.111.0"
from starlette import status as status
# 其他人在使用時,可以不用寫 "from fastapi import applications"
# 而是寫 "from fastapi import FastAPI"
# from <module> import <method>
from .applications import FastAPI as FastAPI
# ...
Strings
Text Sequence Type @ Built-in Types
Functions
一些特殊的屬性
keywords:__name__
, __doc__
, __annotations__
- 使用
fn.__name__
可以的到該函式的名稱 - 使用
fn.__doc__
可以檢視該函式的使用說明(如果有寫 Docstring 的話) - 使用
fn.__annotations__
可以檢視函式參數的型別註記
Positional Arguments vs. Keyword Arguments
def greet(first_name, last_name):
return print(f"Hello, {first_name} {last_name}!")
# 使用 positional arguments
greet("John", "Doe")
# 使用 keyword arguments
greet(last_name="Doe", first_name="John")
在定義函式時可以使用 /
、*
來指定哪些參數只能是 positional arguments、哪些參數只能是 keyword arguments:
/
之前的參數一定要用 Positional Arguments*
之後的參數一定要用 Keyword Arguments
def example_function(a, b, /, c, *, d, e):
print(f"a: {a}, b: {b}, c: {c}, d: {d}, e: {e}")
example_function(1, 2, 3, d=4, e=5) # Correct
example_function(1, 2, c=3, d=4, e=5) # Correct
取得所有傳入的參數
keywords: *args
、**kwargs
在 Python 函式中,可以在參數前面加上 *
,以此來捕捉使用者傳入的任意數量的「Positional Arguments」。這些 Positional Arguments 會被打包成一個元組(tuple),讓你可以處理任意數量的輸入:
# 使用 "*args" 可以把所有輸入的參數變成一個 tuple
# "args" 只是一個變數名稱,可以自己取名
def collect_inputs(*args):
print("You entered:", args)
for i, arg in enumerate(args, 1):
print(f"Argument {i}: {arg}")
collect_inputs("apple", "banana", "cherry")
"""
You entered: ('apple', 'banana', 'cherry')
Argument 1: apple
Argument 2: banana
Argument 3: cherry
"""
在參數前面加上 *
可以取得 Positional Arguments;如果要取得 Keyword Arguments 的話,則要在參數前面加上 **
,例如 **kwargs
。這些 Keyword Arguments 會被包成一個 dict:
# 在參數前面加上 "**" 可以取得 keyword arguments
def collect_inputs(*args, **kwargs):
print("You entered these positional arguments:", args)
for i, arg in enumerate(args, 1):
print(f"Positional Argument {i}: {arg}")
print("You also entered these keyword arguments:")
for key, value in kwargs.items():
print(f"{key}: {value}")
collect_inputs("apple", "banana", "cherry", name="David", age=25)
"""
You entered these positional arguments: ('apple', 'banana', 'cherry')
Positional Argument 1: apple
Positional Argument 2: banana
Positional Argument 3: cherry
You also entered these keyword arguments:
name: David
age: 25
"""
將傳入的參數「解開來」
上面我們是在定義函式的時候使用 *
或 **
,在呼叫函式的時候,也可以使用 *
,但意義上是不同的,如果在呼叫函式時使用 *
,表示要把帶入的參數「解開來」,例如:
fruits = ["apple", "banana", "cherry"]
collect_inputs(*fruits, name="David", age=25)
# 等同於
collect_inputs("apple", "banana", "cherry", name="David", age=25)