資訊之芽 2022 Python 語法班
Author: Sean 韋詠祥
Note:
日期:2022-04-17
課程時間:14:00 - 15:20
Note:
簡報連結已放上課程網站
Note:
PyDoc 的 6. Modules 開頭就講了
# 語法結構
import <模組名稱>
# 舉個例子 🌰
import math
x = math.floor(3.14)
print(x)
Note:
# 語法結構
from <模組> import <模組內的東西>
from <模組> import <子模組>, <函式>, <常數>, <Class>
# 舉個例子 🌰
from string import hexdigits, capwords
print(hexdigits)
print(capwords('hello woRLD'))
Note:
# 語法結構
from <模組> import *
# 舉個例子 🌰
from math import * # 裡面包含 floor, gcd, pi 等函式及變數
n = floor(9 * pi)
print('n =', n)
m = gcd(n, 35)
print('m =', m)
Note:
# 語法結構
import <模組> as <別名>
from <模組> import <東西> as <別名>
# 舉個例子 🌰
import unicodedata as ud
from math import factorial as fact
print('Name 1:', ud.name('!')) # EXCLAMATION MARK
print('Name 2:', ud.name('😼')) # CAT FACE WITH WRY SMILE
print('5! = ', fact(5))
用 Python 計算以下數值
\[ 3^5 \text{ = ?} \\ \sqrt{2} \text{ = ?} \\ \cos (\frac{\pi}{3}) \text{ = ?} \]
Hint: 全部在 math 裡面
sqrt, cos, pow, pi
建立一個名為 fibo.py
的模組檔案
# File: fibo.py
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
在 VS Code 中,請按 ^N (Ctrl-N) 新增檔案
寫完後用 ^S 存檔
Note:
來源:PyDoc Modules Tutorial
https://docs.python.org/3/tutorial/modules.html
import fibo # 前面 fibo.py 檔名,拿掉 .py
fibo.fib(20)
from fibo import fib
fib(20)
在 VS Code 中,點右上角 ▷ 執行程式
在 sprout.py
中,自己定義 fact()
函式
fact(0) = 1
fact(1) = 1 # 1
fact(2) = 2 # 2 * 1
fact(3) = 6 # 3 * 2 * 1
fact(4) = 24 # 4 * 3 * 2 * 1
fact(5) = 120 # 5 * 4 * 3 * 2 * 1
fact(6) = 720 # 6 * 5 * 4 * 3 * 2 * 1
....
fact(15) = 1307674368000 # 15 * 14 * 13 * ... * 2 * 1
Hint: 可以在 def fact()
中遞迴呼叫 fact()
函式
當有一些函式不希望被 import *
進來
# File: sprout.py
__all__ = ['fact']
def is_negative(n):
if n < 0:
return True
return False
def fact(n):
if is_negative(n):
return -1 # Error!
if n > 1:
return n * fact(n-1)
return 1
在 from sprout import *
的時候,只有 __all__
裡面寫到的 fact
會被 import 進來
Note. 但可以被 import sprout
或 from sprout import is_negative
取用
在模組中,還有可以加上…
__author__ = 'Sean Wei'
__version__ = '1.19.2'
__license__ = 'MIT'
__status__ = 'Production'
__email__ = 'me@sean.taipei'
__copyright__ = 'Copyright 2022, Sprout Team'
Note:
The Python Package Index (PyPI) is a repository of software for the Python programming language.
https://pypi.org/
請大家跟著做
可以用 Tab 或 __all__ 找到有效函式、常數
import math
print('gcd:', math.gcd(52, 91)) # 最大公因數
print('lcm:', math.lcm(15, 21)) # 最小公倍數
print('ceil:', math.ceil(4.2)) # 上高斯(無條件進位)
print('floor:', math.floor(4.2)) # 下高斯(無條件捨去)
# 前面是函式,這兩個沒有括號的是常數
print('Natural number:', math.e) # 自然數
print('Pi:', math.pi) # 圓周率 π
Note:
搜尋 "py math"
參考資料
https://docs.python.org/3/library/math.html
import string
# 小寫字母:abcdefghijklmnopqrstuvwxyz
print('Lowercase:', string.ascii_lowercase)
# 標點符號:!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
print('Punctuation:', string.punctuation)
# 可視字元:
print('Printable:', string.printable)
# 0123456789abcdefghijklmnopqrstuvwxyz
# ABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()
# *+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c
Note:
參考資料
https://docs.python.org/3/library/string.html
\t \x09 TAB (horizontal tab)
\n \x0a LF (LN line feed, new line)
\x0b VT (vertical tab)
\x0c FF (NP form feed, new page)
\r \x0d CR (carriage return)
Ref: https://www.asciitable.com/asciifull.gif
import random
# 在 [0, 1) 之間的浮點數
print('Random number:', random.random())
# 在 [1, 5] 之間挑選一個整數
print('Lucky number:', random.randint(1, 5))
# 在 [20, 80) 之間挑選一個浮點數
print('Precipitation:', random.uniform(20, 80))
# 產生內容為 [0, 1, 2, ... 48, 49] 的 list
A = [i for i in range(50)]
print('The list A:', A)
# 在 list 中隨機選一個值
print('Choice one:', random.choice(A))
random.shuffle(A) # 把 A 的順序打亂
print('After shuffle:', A) # 現在 A 被原地修改為新的順序了
Note:
參考資料
https://docs.python.org/3/library/random.html
只要取得幾百個隨機數,就能精準預測後面的其他隨機輸出
https://github.com/tna0y/Python-random-module-cracker
import os
# 取得目前目錄路徑
print('Current working directory:', os.getcwd())
# 列出目錄中檔案,以根目錄為例
print('Files:', os.listdir('/'))
# 建立資料夾
os.mkdir('tmp-py2022-data')
# 移除檔案
os.remove('trash-file')
Note:
參考資料
https://docs.python.org/3/library/os.html
import sys
# 執行的參數列表
print('Arguments:', sys.argv)
# 套件路徑列表
print('Python Path:', sys.path)
# 版本資訊:3.9.12 (main, Mar 26 2022) [Clang 13.1.6]
print('Version:', sys.version)
Note:
參考資料
https://docs.python.org/3/library/sys.html
import time
# 目前秒數:1650177060
print('Time 1:', time.time())
# 中間暫停 1.5 秒
time.sleep(1.5)
# 會比上面的秒數多 1.5 秒
print('Time 2:', time.time())
from datetime import datetime
# 結構化的目前時間:datetime(2022, 4, 17, 14, 55, 20, 123456)
t = datetime.now()
print('Datetime:', repr(t))
# 將時間格式化成指定格式:Sun, 17 Apr 2022
print('Format:', t.strftime('%a, %d %b %Y'))
Note:
參考資料
https://docs.python.org/3/library/time.html
https://docs.python.org/3/library/datetime.html
一班用 time
晚點有空再提 __repr__()
# 矩陣運算
import numpy as np
# 影像處理
import pillow as pil
# 聊天機器人
import discord as dc
# 網頁內容請求
import requests as req
# 網頁爬蟲
import bs4.BeautifulSoup as bs
# 資料視覺化
import matplotlib.pyplot as plt
# Base64 編碼、解碼
import base64.b64encode as b64e
import base64.b64decode as b64d
第 1 行輸入數字 N 代表長度(N ≥ 5)
第 2 行輸入 0 或 1,代表是否要包含大小寫字母
第 3 行輸入 0 或 1,代表是否要包含數字和標點符號
保證第 2 3 行不會同時為 0
使用前面提到的 strings
及 random
函式庫
每次產生 5 個長度為 N 且符合要求的隨機字串
(就算輸入要求有數字,輸出也可以不出現數字,
只要正常隨機就好)
拆成幾十個模組怎麼辦?
總不能全部丟在同個目錄吧
一個專案可能長得像這樣
discord/ 專案頂層目錄
├── __init__.py ├── 初始化 discord 模組的腳本
├── commands/ ├── 指令相關模組
│ ├── __init__.py │
│ ├── options.py │
│ ├── context.py │
│ └── core.py │
├── utils.py │
├── types/ ├── 專案內用到的自定義型別
│ ├── __init__.py │
│ ├── emoji.py │
│ ├── role.py │
│ └── user.py │
└── ui/ └── 介面相關程式碼
├── __init__.py
├── button.py
└── modal.py
我們可以 import 一個 .py 檔案,那資料夾呢?
因此只有包含 __init__.py
的資料夾可以被引入
此檔案中會放初始化模組用的程式碼
並且用 __all__
特殊變數,指定同目錄下要引入哪些檔案或子資料夾
Note:
如果 import 一個套件,就把裡面所有子資料夾全部讀進來,那可能會遇到一些撞名的資料夾或檔案,導致不必要的麻煩
# File: discord/commands/core.py
import request
from discord.ui import modal # /ui/modal.py
# 以下使用相對名稱 import
import ..utils # /utils.py
from . import options # /commands/options.py
from .context import response # /commands/context.py:response
from ..types import user # /types/user.py
from ..types.role import color # /types/role.py:color
找不到這個變數
base64.b64decode('U3Byb3V0IDIwMjI=')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'base64' is not defined
確定有 import 相關模組
import <缺少的模組>
import base64
找不到這個模組
import discord
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'discord'
使用 pip 安裝相應套件
$ pip install <缺少的套件>
C:\Users\sean> pip
'pip' is not recognized as an internal or external command,
operable program or batch file.
到 Python 官網安裝
Note:
在這邊確保大家的環境是一致的
先上程式碼
# File: math.py
import math
print(math.gcd(42, 18))
錯誤訊息
Traceback (most recent call last):
File ".../math.py", line 1, in <module>
import math
File ".../math.py", line 3, in <module>
print(math.gcd(4, 6))
AttributeError: partially initialized module 'math' has no
attribute 'gcd' (most likely due to a circular import)
為什麼呢?
Note:
這裡的 import math 是自己 math.py 的意思
# File: main.py
from foo import func1
func1()
# File: foo.py | # File: bar.py
from bar import func2 | from foo import func3
def func1(): | def func2():
func2() | print('Hey there!')
def func3(): | func3()
print('Goodbye~') |
Traceback (most recent call last):
File ".../main.py", line 1, in <module>
from foo import func1
File ".../foo.py", line 1, in <module>
from bar import func2
File ".../bar.py", line 1, in <module>
from foo import func3
ImportError: cannot import name 'func3' from
partially initialized module 'foo' (most likely
due to a circular import) (.../foo.py)
Note:
即使此案例中 function 本身沒有造成迴圈也會出錯
很重要但下週才會教的 Coding Style
# ✅ 正確寫法
import os
import sys
# ❌ 錯誤示範
import sys, os
# ✅ 這樣也是正確的
from subprocess import Popen, PIPE
#!/usr/bin/env python
"""Script for sprout demo
Meow meow meow meow meow
"""
import os
import math
_USAGE = 'Just run this script. :)'
import os
import string
from time import sleep
from datetime import datetime
import discord
import requests as req
from discord.ext import commands
import sproututils
__future__
等特殊 import"""This is the example module.
This module does stuff.
"""
from __future__ import annotations
__all__ = ['fact', 'exgcd', 'c']
__version__ = '0.1'
__author__ = 'Sprout 2022 Team'
import os
import sys
import datetime
t = datetime.datetime.now()
print('Case A:', t)
print('Case B:', str(t))
print('Case C:', repr(t))
s = repr(t) # 取得給直譯器看的 representation 格式
type(s) # 確認得到的是個字串 (str)
n = eval(s) # 把 str 轉換回 datetime
type(n) # 確認轉換成功
Note:
參考文章:repr 與 str 雜談
https://ithelp.ithome.com.tw/articles/10194593
投影片連結:https://hackmd.io/@Sean64/py-module-sprout2022
import __hello__
# Hello world!
import this
# The Zen of Python, by Tim Peters
#
# Beautiful is better than ugly.
# Explicit is better than implicit.
# Simple is better than complex.
# Complex is better than complicated.
# [...]
from __future__ import braces
# SyntaxError: not a chance
# xkcd
import antigravity
# Geohashing: https://xkcd.com/426/
antigravity.geohash(24.787, 120.997, b'Meow')