Python程式設計

Lesson 9: 模組與套件

Last updated: 2022/10/11

Outline

  • 模組
  • 套件
  • 亂數模組: random
  • 時間模組: time

模組module

多個「自訂函式」的集合

def 函式A():
    ...
    return ...
    
def 函式B():
    ...
    return ...
    
# 沒有主程式

模組簡介: 函式轉成模組(1/4)

原Python檔案

# 自訂函式
def Km2Mile(distance):
    mile = distance/1.609
    return mile         

# 主程式開始
speed = Km2Mile(150)    
print('%6.1f' % speed)
import converter    # 匯入自訂模組

km = 100
mile = converter.Km2Mile(km)    # 呼叫模組的功能
print('%d公里 =%8.2f英哩' % (km, mile))

僅保留函式

# 取任意名,例如:converter.py
# 提供公里轉英里的功能
def Km2Mile(distance):
    mile = distance/1.609
    return mile

# 沒有主程式

模組:converter.py

另建新檔寫主程式
使用模組功能

建立模組檔

import 模組名稱

模組名稱.函式名稱

新的主程式py檔

模組簡介: 函式轉成模組(2/4)

import converter    # 匯入自訂模組

km = 100
mile = converter.Km2Mile(km)    # 呼叫模組的功能
print('%d公里 =%8.2f英哩' % (km, mile))

模組: 功能函式儲存同一檔案, 供其他程式使用

方便重複使用

# 取任意名,例如:converter.py
# 提供公里轉英里的功能
def Km2Mile(distance):
    mile = distance/1.609
    return mile

模組:converter.py

作業1.py

import converter    # 引入模組

while True:
    km = int(input('輸入公里數(0程式結束):'))
    if (km == 0):
        break
    mile = converter.Km2Mile(km)    # 呼叫模組功能
    print('%d公里 =%8.2f英哩' % (km, mile)) 
print('程式結束')

作業2.py

模組簡介: 函式轉成模組(3/4)

範例:實作模組,可以隨機回傳「剪刀」、「石頭」、「布」三者其中之一

import random    # python常用模組

status = ['剪刀', '石頭', '布']

def guess():
    """提供guess功能, 回傳剪刀、石頭、布三者任一"""
    return random.choice(status)

模組:guess.py

import guess    # 引入模組

computer = guess.guess()  # 呼叫guess()功能
print(computer)

範例主程式.py

模組簡介: 函式轉成模組(4/4)

練習:撰寫一模組rectangle.py,提供計算面積area(), perimeter() 

def area(width, height):
    # 計算面積
    # return 面積
    
def perimeter(width, height):
    # 計算周長
    # return 周長

模組:rectangle.py

import rectangle

寬 = int(input('輸入四邊形寬:'))
高 = int(input('輸入四邊形高'))
面積 = rectangle.area(寬, 高)
周長 = rectangle.perimeter(寬, 高)
print('四邊形寬高為: %d x %d' % (寬, 高))
print('面積與周長為: %d, %d' % (面積, 周長))

練習主程式.py

模組模組函式使用方式(1/9)

def Menu():    # 印出預購折扣表
    print('='*10)
    print('1. 1杯無折扣')
    print('2. 10杯62折')
    print('3. 50杯58折')
    print('4. 99杯53折')
    print('0. 結束')
    print('='*10)

def Total(數量, 單價, 折扣=1.0):  # 計算總價與減價
    減價 = 數量*單價*(1.0-折扣)
    return 減價, 數量*單價*折扣   # 回傳 減價與總價

模組:sale.py

import 模組名稱

import sale

price = 45    # 單價45元
amount = [1, 10, 50, 99]  # 杯數串列
折扣數 = [1.0, 0.62, 0.58, 0.53]  # 折扣串列
sale.Menu()
decision = int(input('你的選擇是:'))
    
if decision>0 and decision<5:
    save, total = sale.Total(amount[decision-1], price, 折扣數[decision-1])
    print('購買數量 %d, 總價%d, 節省%d' % (amount[decision-1], total, save))
else: 
    print('選項輸入錯誤')

模組使用方法1

函式呼叫:模組名稱.函式名稱()

ex01.py

模組模組函式使用方式(2/9)

from 模組名稱 import 函式名稱

from sale import Total
from sale import Menu

price = 45    # 單價45元
amount = [1, 10, 50, 99]  # 杯數串列
折扣數 = [1.0, 0.62, 0.58, 0.53]  # 折扣串列
Menu()
decision = int(input('你的選擇是:'))
    
if decision>0 and decision<5:
    save, total = Total(amount[decision-1], price, 折扣數[decision-1])
    print('購買數量 %d, 總價%d, 節省%d' % (amount[decision-1], total, save))
else: 
    print('選項輸入錯誤')

模組使用方法2: 只引入特定函式

函式呼叫時,只需使用 函式名稱()

模組模組函式使用方式(3/9)

from 模組名稱 import 函式1, 函式2,...

from sale import Total, Menu

price = 45    # 單價45元
amount = [1, 10, 50, 99]  # 杯數串列
折扣數 = [1.0, 0.62, 0.58, 0.53]  # 折扣串列
Menu()
decision = int(input('你的選擇是:'))
    
if decision>0 and decision<5:
    save, total = Total(amount[decision-1], price, 折扣數[decision-1])
    print('購買數量 %d, 總價%d, 節省%d' % (amount[decision-1], total, save))
else: 
    print('選項輸入錯誤')

模組使用方法3: 引入多個函式

函式呼叫時,只需使用 函式名稱()

模組模組函式使用方式(4/9)

from 模組名稱 import *

from sale import *

price = 45    # 單價45元
amount = [1, 10, 50, 99]  # 杯數串列
折扣數 = [1.0, 0.62, 0.58, 0.53]  # 折扣串列
Menu()
decision = int(input('你的選擇是:'))
    
if decision>0 and decision<5:
    save, total = Total(amount[decision-1], price, 折扣數[decision-1])
    print('購買數量 %d, 總價%d, 節省%d' % (amount[decision-1], total, save))
else: 
    print('選項輸入錯誤')

模組使用方法4: 引入所有函式

函式呼叫時,只需使用 函式名稱()

模組模組函式使用方式(5/9)

from 模組名稱 import *

函式呼叫時,只需使用 函式名稱()

import 模組名稱

函式呼叫:模組名稱.函式名稱()

def area(width, height):
    # 計算面積
    # return 面積
    
def perimeter(width, height):
    # 計算周長
    # return 周長

模組:rectangle.py

import rectangle

寬 = int(input('輸入四邊形寬:'))
高 = int(input('輸入四邊形高'))
面積 = rectangle.area(寬, 高)
周長 = rectangle.perimeter(寬, 高)
print('四邊形寬高為: %d x %d' % (寬, 高))
print('面積與周長為: %d, %d' % (面積, 周長))
from rectangle import *

寬 = int(input('輸入四邊形寬:'))
高 = int(input('輸入四邊形高'))
面積 = area(寬, 高)
周長 = perimeter(寬, 高)
print('四邊形寬高為: %d x %d' % (寬, 高))
print('面積與周長為: %d, %d' % (面積, 周長))

ex02.py

ex02.py

寫法1

寫法2

模組模組函式使用方式(6/9)

練習:建立模組dice.py,提供一dice()功能,傳回擲出的點數(隨機產生1~6)

# dice.py模組
from random import choice
點數 = [1, 2, 3, 4, 5, 6]
def dice():
    return choice(點數)

模組:dice.py

import dice    # 引入模組dice.py    

# 呼叫dice.dice(),共產生10次點數
for count in range(1,11):
    print('第%d輪的點數是: %d' % (count, dice.dice()))

ex03.py

模組模組函式使用方式(7/9)

實作:樂透模組exlotto.py。該模組內有一個函式lotto,可以從1到n個數字中,取m個數字製作中獎號碼串列,回傳中獎號碼串列

# exlotto.py模組
from random import choice

def lotto(n, m):
    """n: 數字1到n,可以用range(1, n+1)建立"""
    """m: 取m個數字,但不可重複"""
    ...

模組:exlotto.py

另外撰寫主程式 hw6-1.py,呼叫上述模組的lotto(),並印出中獎號碼

# 函式用法提示1
from random import choice

數列 = [1,2 ,3, 4]   # 任意數列
數值 = choice(數列)   #  隨機挑出一個
# 函式用法提示2

數列 = [1,2 ,3, 4]   # 任意數列
數列.remove(3)  # 移除數列中第一個3
print(數列)     # 印出[1,2,4]

模組模組函式使用方式(8/9)

import 模組名稱 as 替代名稱

函式呼叫:替代名稱.函式名稱()

import sale as s    #用簡單名稱取代原先模組名稱
import random as r

...
sale.Menu()
....
r.choice()

模組模組函式使用方式(9/9)

練習:建立模組dice.py,提供一dice()功能,傳回擲出的點數(隨機產生1~6)

改用import ... as ...

# dice.py模組
from random import choice
點數 = [1, 2, 3, 4, 5, 6]
def dice():
    return choice(點數)

模組:dice.py

import dice as d   # 引入模組dice.py    

# 呼叫dice.dice(),共產生10次點數
for count in range(1,11):
    print('第%d輪的點數是: %d' % (count, d.dice()))

套件

一個「資料夾」內包含多個模組,及一個獨立檔案__init__.py

套件

模組2

模組N

模組1

...

__init__.py

套件簡介: 多個模組合成套件(1/4)

# 取任意名,例如:distance.py
# 提供公里轉英里的功能
def Km2Mile(distance):
    mile = distance/1.609
    return mile

# 沒有主程式

模組:distance.py

# 取任意名,例如:degree.py
# 提供華氏轉攝氏的功能
def c2f(degree):
    f = degree * 1.8 + 32
    return f

# 沒有主程式

模組:degree.py

__init__.py

資料夾: converter

套件:多個模組放在同一個資料夾下,並新增__init__.py

converter套件,內含兩個模組distance, degree

套件簡介: 多個模組合成套件(2/4)

套件:多個模組放在同一個資料夾下,並新增__init__.py

game套件,內含兩個模組dice, poker

套件套件使用(3/4)

from 套件名稱 import 模組名稱

函式呼叫:模組名稱.函式名稱()

# 取任意名,例如:distance.py
# 提供公里轉英里的功能
def Km2Mile(distance):
    mile = distance/1.609
    return mile

# 沒有主程式

模組:distance.py

# 取任意名,例如:degree.py
# 提供華氏轉攝氏的功能
def c2f(degree):
    f = degree * 1.8 + 32
    return f

# 沒有主程式

模組:degree.py

__init__.py

資料夾: converter

from convert import distance, degree

print(distance.Km2Mile(100))
print(degree.c2f(10))

範例1.py

套件套件使用(4/4)

from 套件名稱 import 模組名稱

函式呼叫:模組名稱.函式名稱()

from random import choice

def dice():
    return choice(range(1,7))

模組:dice.py

from random import choice

def poker():
    a = ['C', 'H', 'D', 'S']
    b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 'T', 'J', 'Q', 'K']
    return choice(a) + str(choice(b))

模組:poker.py

__init__.py

資料夾: game

from game import dice, poker

for i in range(2):
    print(dice.dice())
    print(poker.poker())

範例2.py

模組標準函式庫

亂數模組(1/11)

亂數(隨機數): 平均散佈在「某個區間」的數字

亂數模組常用方法randint() (2/11)

❶ randint(min, max): 隨機產生介於min與max之間的整數

import random
...
dice = random.randint(1,6)    # 隨機產生1~6點
import random
...
poker = random.randint(0, 51) # 產生0~51之間的數字

花色 = poker // 13       # 整數除法-> 0~3, 0黑桃,1紅心...
點數 = (poker % 13)   # 0~12 -> A,2,3,...10,J,Q,K

亂數模組常用方法randint() (3/11)

import porker

c, p = poker.pick()
print(f'抽到的牌是{c} {p}')
import random

花色 = ['黑桃', '紅心', '方塊', '梅花']
點數 = ['A','2','3','4','5','6','7','8','9','10','J','Q','K']

def pick():
    '''挑一張牌'''
    num = random.randint(1, 52) # 隨機挑一張
    card = 花色[num // 13]      # 整數除法結果為0,1,2,3
    point = 點數[num % 13]      # 餘數 0~12      
    return card, point

模組:poker.py

主程式:main01.py

亂數模組常用方法randint() (4/11)

import porker

for i in range(52):
    c, p = poker.draw()
    print(f'抽到的牌是{c} {p}')
import random

花色 = ['黑桃', '紅心', '方塊', '梅花']
點數 = ['A','2','3','4','5','6','7','8','9','10','J','Q','K']
folder = [i for i in range(52)] # 產生0~51的串列

def pick():
    '''挑一張牌'''
    num = random.randint(0, 51) # 隨機挑一張
    card = 花色[num // 13]      # 整數除法結果為0,1,2,3
    point = 點數[num % 13]      # 餘數 0~12      
    return card, point

def draw():
    '''發牌'''
    while True:
        num = random.randint(0, 51) # 隨機挑一張
        if num in folder:    # 牌還在
            card = 花色[num // 13]      # 整數除法結果為0,1,2,3
            point = 點數[num % 13]      # 餘數 0~12
            folder.remove(num)
            print(folder)
            break
    return card, point

模組更新版:poker.py

主程式:main02.py

亂數模組常用方法randint() (5/11)

# 印出10個點數
import random

for i in range(1,11):
    num = random.randint(1,6)    # 隨機產生1~6點
    print(num)

範例:印出10次擲骰子的點數

亂數模組常用方法randint() (6/11)

練習:統計骰子點數1~6各出現幾次

挑戰:如何累計次數,存在何處?可使用串列(list)

import random

擲骰子次數 = 100
統計串列 = [0] * 6    # 產生[0, 0, 0, 0, 0, 0]
for i in range(1, 擲骰子次數+1):
    dice = random.randint(1, 6)    # 擲骰子
    統計串列[dice-1] += 1  # 統計

print(統計串列)       # 印出統計結果

執行結果:[16, 22, 17, 7, 20, 18]

亂數模組常用方法randint() (7/11)

範例:猜數字遊戲-由亂數產生答案(介於1~100)

  • 使用者猜測答案後,印出"猜大一些", "猜小一些", 或"答對了"
  • 最後印出使用者猜了多少次
import random

answer = random.randint(1,100)    # 產生答案
次數 = 0        # 猜測次數歸零
while True:
    guess = int(input("輸入1~100之間的整數:"))
    次數 += 1    # 猜測次數多1次
    if (guess == answer):
        print("你答對了!")
        break
    if (guess > answer):
        print('猜小一點')
    else:
        print('猜大一點')
print('總共猜了%d次' % 次數)

亂數模組常用方法randint() (8/11)

練習:隨機產生2000張撲克牌,並統計每張撲克牌各出現幾次
印出 黑桃A: 38次, 黑桃2: 40次....

import random
...
poker = random.randint(0, 51) # 產生1~52

花色 = poker // 13       # 整數除法-> 0~3, 0黑桃,1紅心...
點數 = (poker % 13)      # 0~12 -> A,2,3,...10,J,Q,K

提示:

亂數模組常用方法choice() (9/11)

❷ choice(串列名稱): 隨機從串列中回傳一個元素

import random

fruits = ['蘋果', '鳳梨', '香蕉', '芭樂']

def pick():  # 注意下一行的註解
    '''隨機回傳水果的種類 '''
    return random.choice(fruits)
import fruit

# 主程式
水果 = fruit.pick()
print(f'今天飯後水果是: {水果}')

模組:fruit.py

主程式:main.py

亂數模組常用方法choice() (10/11)

範例:網購T恤,T恤有紅藍綠黑白5種顏色,採隨機出貨,請在輸入數量後,印出出貨的數量與顏色

import random

顏色 = ['紅', '綠', '藍', '白', '黑']
統計 = dict()  # 以字典統計數量:{'紅': 2, '白': 2, '黑': 1}
數量 = int(input('請輸入數量:'))
for i in range(數量):
    挑選 = random.choice(顏色)  # 隨機出貨
    if (挑選 in 統計):    # 顏色已在字典中
        統計[挑選] += 1   # 加1
    else:                # 顏色不在字典中
        統計[挑選] = 1    # 加入字典, 初值為1
# 輸出結果
print('總共買%d件' % 數量)
for key, value in 統計.items():
    print("%s色有%d件" % (key, int(value)))

亂數模組常用方法choice() (11/11)

練習:請改寫下列統計骰子出現次數的範例,改用choice() 

import random

擲骰子次數 = 100
統計串列 = [0] * 6    # 產生[0, 0, 0, 0, 0, 0]
for i in range(擲骰子次數):
    dice = random.randint(1, 6)    # 擲骰子
    統計串列[dice-1] += 1  # 統計

print(統計串列)       # 印出統計結果

時間模組(1/10)

時間模組: 可用來計算「程式執行的時間」、或抓取系統的「日期與時間」

日曆、時間

碼表

排程

時間模組time() (2/10)

❶ time(): 回傳自1970/1/1 00:00:00AM以來的秒數UNIX紀元

import time

seconds = float(time.time())    # 抓取系統當時的時間
print(f'自1970/1/1 00:00:00AM以來,過了{seconds:8.2f}秒')
import time

開始秒數 = float(time.time())
###
#  想要計算執行秒數的程式碼在此
###
結束秒數 = float(time.time())
print(f'執行時間 {結束秒數-開始秒數:8.2f}')

時間模組time() (3/10)

範例:修改「骰子點數出現次數」的範例,加上時間函數time(),最後印出程式執行所需的時間

import random, time

擲骰子次數 = 100
統計串列 = [0] * 6    # 產生[0, 0, 0, 0, 0, 0]
start = time.time()
for i in range(1, 擲骰子次數+1):
    dice = random.randint(1, 6)    # 擲骰子
    統計串列[dice-1] += 1  # 統計
end = time.time()
print(f'執行時間是 {end-start:10.5f}')
print(統計串列)       # 印出統計結果

時間模組time() (4/10)

範例:修改猜數字遊戲範例,觀察程式執行的時間

import random

answer = random.randint(1,100)    # 產生答案
次數 = 0        # 猜測次數歸零
while True:
    guess = int(input("輸入1~100之間的整數:"))
    次數 += 1    # 猜測次數多1次
    if (guess == answer):
        print("你答對了!")
        break
    if (guess > answer):
        print('猜小一點')
    else:
        print('猜大一點')
print('總共猜了%d次' % 次數)

時間模組time() (5/10)

練習:修改前頁範例,改為依序輸出100, 1000, 10000, 100000次的執行時間各為多少(在同一程式裡)

import random, time
# 可改為串列
擲骰子次數 = [100, 1000, 10000, 100000]

# 雙層for迴圈
# 外層處理次數
#    內層處理擲骰子, 與統計次數
#    

時間模組sleep() (6/10)

import time
# 從10倒數到1
for i in range(10, 0, -1):
    print(i)
    time.sleep(1.0)
print('時間到')

❷ sleep(秒數): 讓程式工作暫停N秒鐘,可用於動畫設計

時間模組sleep() (7/10)

import time
import sys
# 從10倒數到1
for i in range(10, 0, -1):
    print(str(i).zfill(2) + '\r', end='' )
    time.sleep(1.0)
print('時間到')

範例:再搭配使用印出'\r'字元(歸位鍵),可做成倒數計時器

str(10).zfill(2)  # 印出10
str(9).zfile(2)   # 印出09

時間模組sleep() (8/10)

練習:輸入秒數,做成如上頁的倒數計時器,輸出格式為hh:mm:ss

# 提示:內建函式divmod(總秒數, 60) 可回傳'分','秒'
總秒數 = 12345
分鐘,秒數 = divmod(總秒數, 60)
小時,分鐘 = divmod(分鐘, 60)
print(str(小時), str(分鐘), str(秒數))
print(str(小時).zfill(2), str(分鐘).zfill(2), str(秒數).zfill(2))

3 25 45
03 25 45

時間模組localtime() (9/10)

❸localtime(): 回傳目前的時間結構資料串列。

import time

目前時間 = time.localtime()
print(目前時間)

time.struct_time(tm_year=2019, tm_mon=10, tm_mday=21, tm_hour=14, tm_min=54, tm_sec=34, tm_wday=0, tm_yday=294, tm_isdst=0)

import time

目前時間 = time.localtime()
print(目前時間)   # 目前時間為一tuple
print('年:', 目前時間[0])  # 索引值0為年
print('月:', 目前時間[1])  # 索引值1為月
print('日:', 目前時間[2])  # 索引值2為日
print('時:', 目前時間[3])  # 索引值3為時
print('分:', 目前時間[4])  # 索引值4為分
print('秒:', 目前時間[5])  # 索引值5為秒
print('星期幾:', 目前時間[6])  # 0為星期一
print('第幾天:', 目前時間[7])  # 一年中的第幾天
print('夏令時間:', 目前時間[8]) # 0為非夏令時間

時間模組localtime() (10/10)

練習:使用localtime改寫倒數計時

import time

目前時間 = time.localtime()
print(目前時間)

Python程式設計

By Leuo-Hong Wang

Python程式設計

Lesson 9: 模組與套件

  • 2,305