--- title: Python筆記本 tag: python --- # python記事本 ## 簡介 非本科系學程式找工作 https://www.youtube.com/@pygit-docker/playlists - 項目多元化,python,Django Flask,FastAPI - 專項 Git,Linux,Shell,Container Devops <details> <summary>📁 課程總進度</summary> - [基礎語法](#第一天) - [TQC-python](#第二天) - [檔案讀取與寫入](#第三天) - [函式(Function)]() - [Tkinter模組](#第四天) - [數據資料的儲存與讀取](#第五天) - [猜數字遊戲](#第六天) - [錯誤處理](#第七天) - [類別與物件](#第八天) - [建立自己的模組](#第九天) - [函式(Function)](#第十天) - [numpy](#第十一天) - [網頁資料擷取與分析](#第十二天) </details>details> <a id="第一天"></a> # 基礎語法 ## 字串的格式化操作 ```python= name = "nameless" age = 30 # "I'am nameless, and 30 years old." print("I'am " + name + ", and " + str(age) + " years old.") print("I'am %s, and %d years old." % (name, age)) # age = "30" print("I'am %s, and %s years old." % (name, age)) # 上面%d要改為%s print("I'am {}, and {} years old.".format(name, age)) print("I'am {name}, and {age} years old.".format(name=name, age=age)) print("I'am {1}, and {0} years old.".format(age, name)) print(f"I'am { name}, and {age} years old.") # 推薦做法 ``` ## if判斷式 如何在判斷語句中來判斷True或False bool 是一種資料類型,用來表示布林值 bool(1) 任何 非零數字(正數或負數)都會轉換為 True。 那在python中有那些布林值是False 它是空的列表與布林值無關,所以回傳False ```python= fales_value = [False, [], {}, "", 0, 0.0, None] for val in fales_value: print(True if val else False) # if val: # print(True) # else: # print(False) # print(f"{val} is {bool(val)}") # 全部都是False ``` 我們知道 Python 內置了一些常見的數據類型 如果說我們有一個自定義的數據類型 可以表示True或False ```python= class MyType: def __init__(self): self.value = [] def add(self, x): self.value.append(x) def __bool__(self): return bool(self.value) my_type = MyType() bool(my_type) # False my_type.add(1) bool(my_type) # True print(True if my_type else False) # True ``` ### 如何正確使用返回值 None 如何正確使用返回值 None, 並了解它在程式中的應用。下面的範例包含了三個函式 我們將透過這些函式來模擬連線測試和用戶資料的獲取。 ```python= def test_connection(): return True def get(): return [] # return ["user1", "user2", "user3"] def get_user_list(): if not test_connection(): return None else: return get() user_list = get_user_list() # if not user_list: if user_list is None: print("Connection error") # if not user_list: else: print(user_list) ``` 最後做法 ```python= def test_connection(): return True def get(): return [] def get_user_list(): if not test_connection(): return None return get() user_list = get_user_list() if user_list is None: print("Connection error") print("user_list:", user_list) ``` user_list是False的原因是什麼?因為它是一個空的list 可是呢?我們一開始給它test_connection 是回傳True,它是成功的,表示邏輯上的錯誤 它的布林值有多種返回值而且是相同的 例如說:None,返回False,而且return get() 是空的list,返回也是False 這樣就不好區分了,所以為了做區分 我們要重新修改,去明確的定義 ### if判斷式優化 今天來介紹if判斷式,大家可以複製我的程式碼就可以了 主要是介紹如何修改,打字不是重點 當我的判斷條件較多的時候,那代碼要怎麼優化 這個value假設是1,那就是Condition.A以此類推 如果choice等於condition.A或等於 condition.B 或等於condition.C的情況下 印出結果1,否則呢?印出結果2 可是這樣寫可能有點問題? 這個choice一共就四種選擇,if判斷式A,B,C 剩下的條件就等D,對吧!它不可能等於其它的值 ```python= import random from enum import Enum class Condition(Enum): A = 1 B = 2 C = 3 D = 4 print(repr(Condition.A)) print(Condition.A.name) print(Condition.A.value) values = [1, 2, 3, 4] choice = Condition(random.choice(values)) if choice == Condition.D: print("result_2") else: print("result_1") # if choice == Condition.A or choice == Condition.B or choice == Condition.C: # print("result_1") # else: # print("result_2") ``` - 用list的方式最好 ```python= values = [1, 2, 3, 4] choice = Condition(random.choice(values)) option = [Condition.A, Condition.B] if choice in option: # if choice == Condition.A or choice == Condition.B: print("result_1") else: print("result_2") ``` ## 元組/數組(Tuple) 在 Python 中,元組(Tuple)是一種不允許變更的資料結構,用來儲存一系列有順序的元素。雖然元組與串列非常相似,但其最大的不同在於,元組中的元素一旦設置後,就無法再進行修改、刪除或新增,因此元組的內容是固定的。 以下是元組的主要特點: - 不可變性(Immutable):一旦元組被創建,它的內容無法進行任何更改,也不能添加或刪除元素。這使得元組屬於不可變資料結構。 - 有序性(Ordered):元組中的元素是依照插入的順序進行排列的,並且這個順序會保持不變。 - 多樣性(Heterogeneous):元組可以包含不同類型的元素,像是整數、浮點數、字串等,可以用來儲存各種不同的資料類型。 ```python= my_tuple = (1, "二", 3, 4.0, 5) my_tuple[1] = "三", print(my_tuyple[1]) # 'tuple' object does not support item assignment ``` ```python= # 訪問元組中的元素 my_tuple = (1, "二", 3, 4.0, 5) print(my_tuple[0]) # 1 print(my_tuple[1]) # "二" # 可以支援字串切片 my_tuple = (1, "二", 3, 4.0, 5) slice_tuple = my_tuple[1:4] print(slice_tuple) # ('二', 3, 4.0) # 可以尋找長度 print(len(my_tuple)) # 5 ``` ```python= test = (1) print(type(test)) # 會印出整數int # <class 'int'> ``` 印出型態之後.會發現是整數 原因是小括號除了代表tuple宣告的值以外 它還代表了四則運算的優先運算 那你可能會說,我就是只想要有一個tuple 裡面有一個值,要怎麼做? ```python= test = (1,) <class 'tuple'> ``` 改為一個逗號,再執行一次就會變成tuple了 ```python= test = [1] print(type(test)) # <class 'list'> ``` 要特別注意的是在宣告元組時如果只有一個元素要記得加上逗號,不然 Python 不會將他視為元組。 ```python= a = (1) print(type(a)) # 輸出:<class 'int'> b = (1,) print(type(b)) # 輸出:<class 'tuple'> ``` 元組(tuple)也可以使用 count() 和 index() 方法,這些方法的使用方式與串列(list)相同。 然而,若想要將元素新增到元組中,可以透過 += 來達成類似的效果。不過需要注意,這樣的操作會創建一個新的元組,並將原來的元組與新元素結合,而不是直接修改原有的元組。這點與串列的 append() 方法不同,因為 append() 會直接修改原串列。 ```python= my_tuple += (1,) ``` ```python= test_02 = () print(id(test_02)) test_02 += (1,) print(test_02) print(id(test_02)) ``` 會看到不同id 以下我再做個實驗,改為list ```python= test_03 = [] print(id(test_03)) test_03.append(1) print(id(test_03)) ``` 會看到相同id ## 串列 這裡簡單做一個購物清單.先定義一個空列表,中括號表示 我要附加東西進去,可以用append 方法一般在操作對象後面加點方法名,小括號(),就可以被調用 ```python= shopping_list = [] # shopping_list.append("滑鼠") # shopping_list.append("鍵盤") # shopping_list.append("螢幕") # shopping_list.append("音響") shopping_list.extend(["滑鼠", "鍵盤", "螢幕", "音響"]) print(shopping_list) ``` extend() 方法是用來將一個可迭代對象,(例如另一個列表)中的元素添加到原來的列表中或者是用運算符 ```python= shopping_list += ["滑鼠", "鍵盤", "螢幕", "音響"] print(shopping_list) ``` ```python= print(len(shopping_list)) # 印出長度 print(shopping_list[0]) # 找索引值 shopping_list[1] = "主機" # 將鍵盤替換成主機 shopping_list # 將結果印出 ``` ### zip函數合併資料 我有兩個列表,一個是數字,一個是字母 這樣做可能比較慢一點,因為我們都用索引的方式 ```python= x = [1, 2, 3, 4] y = ["a", "b", "c", "d"] # {'a': 1, 'b': 2, 'c': 3, 'd': 4} d = {} for i in range(len(x)): d[y[i]] = x[i] print(d) ``` 可以透過python一個函數叫做zip 會將兩個列表中對應位置的元素“壓縮”成元組 並返回一個可迭代的對象 ```python= dict(zip(y, x)) ``` ### 列表解析 ```python= a = [1, 2, 3, 4, 5, 6, 7] b= [] for i in a: if i % 2 == 0: b.append(i) print(b) ``` ```python= 可以改寫為 a = [1, 2, 3, 4, 5, 6, 7] b= [i for i in a if i % 2 == 0] print(b) ``` - 測試用1 ```python= import time start = time.time() b = [] for i in a: if i % 2 == 0: b.append(i) print(time.time() - start) ``` - 測試用2 ```python= import time start = time.time() b = [i for i in a if i % 2 == 0] print(time.time() - start) print(type(b)) ``` 可以比較測試1還有測試2的執行速度 ### 串列操作 list1 = [1, 2, 3, 4, 5, 6] ```python= print(len(list1)) # 長度 6 print(max(list1)) # 最大值 6 print(min(list1)) # 最小值 1 print(list1.index(3)) # 查看3的索引值 2 print(list1.count(3)) # 查看3出現的次數 1次 ``` 假設串列重複兩次 ```python= list2 = list1 * 2 list2 # [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] ``` ### 以串列計算班級成績 學生成績須輸入串列中,變成串列元素 如果輸入[-1],表示成績結束,最後顯示班上總成績和平均成績 總成績與平均成績至小數點第二位 ![image](https://hackmd.io/_uploads/ByqCHlBvkl.png) <details> <summary>點此展開程式碼</summary> ```python= score = [] total = incore = 0 while incore != -1: incore = int(input("請輸入分數: ")) score.append(incore) print(f"共有幾位學生: {len(score) - 1}") for i in range(0, len(score) - 1): total += score[i] avg = total / (len(score) - 1) print(f"總成績為: {total:.2f},平均成績為: {avg:.2f}") ``` </details> ## 字典 字典(Dictionary)是一種無序的資料結構,用來儲存由鍵(Key)與對應的值(Value)組成的對。你可以透過鍵來快速查詢相關聯的值。 字典的主要特點包括: 無序性(Unordered):字典內的元素並沒有特定的順序,因此無法像串列那樣使用索引來存取。必須根據鍵來獲取相應的值。 可變性(Mutable):字典是可變的,這表示可以對字典中的內容進行修改、刪除或新增元素。 唯一鍵(Unique Keys):字典中的鍵必須是唯一的,不能出現重複的鍵。每個鍵只能對應到一個值。 ```python= l = [1, 2, 3, 4] a = { "one": 1, "two": 2, "three": 3, "four": 4, } ``` 何謂唯一值 ```python= a = { "one": 1, "two": 2, "three": 3, "four": 4, "one": 11, "one": 111, } print(a["one"]) # 111 ``` ```python= my_dict = {'one': 1, 'two': 2, 'three': 3, 'four': 4} print(my_dict) # {'three': 3, 'one': 1, 'four': 4, 'two': 2} ``` ### 字典的建立: 透過 {} 來建立字典並透過 : 分隔鍵與值 ```python= person = { "姓名": "Nameless", "年齡": 30, "職業": "找工作", } ``` 字典的查詢: 取得字典值的方法與串列的類似,只是 [] 中傳入的不是索引值而是鍵 ```python= print("姓名:", person["姓名"]) # 輸出:姓名:Nameless print("年齡:", person["年齡"]) # 輸出:年齡:30 print("職業:", person["職業"]) # 輸出:職業:找工作 ``` 要注意的是如果使用 [] 訪問值,如果指定的鍵不存在則會引發 KeyError 錯誤,這時可以透過 get() 進行查詢,這樣如果找不到指定鍵的值則會回傳 None。 ```python= print(person.get("地址")) # 輸出:None 你也可以透過指定預設值的方式,讓 get() 在找不到對應的值時回傳預設值給你 ``` 那你可能會說,我不要它回傳None 你可以這樣做 ```python= print(person.get("地址", "無地址")) ``` ```python= print(person.get("性別", "未知")) # 輸出:未知 ``` 取得所有的key,values,可以這樣做 ```python= print(person.keys()) # 取得所有鍵 print(person.values()) # 取得所有值 ``` ### 字典與迴圈有三種搭配方式 ```python= person = { "姓名": "Nameless", "年齡": 30, "職業": "找工作", } for key, value in person.items(): print(key, ":", value) # for value in person.values(): # print(value) # 印出value # for key in person.keys(): # print(key) # 印出key ``` ### 字典解析 a串列,我們要生成一個字典,必須有key和value對吧! 那它的key就是1,2,3,4,5 value就是對應的值,結果類似像這樣 我希望value是字串型態 {1:"1",2:"2"} ```python= a = [1, 2, 3, 4, 5,] c = {item: str(item) for item in a} print(c) print(type(c)) # {1:"1",2:"2"} ``` ```python= d1 = {"name": "nameless", "age": 35} d2 = {"ver": 3.6, "platform": "Linux"} d3 = {"size": "50MB"} a = {} for key, value in d1.items(): a[key] = value for key, value in d2.items(): a[key] = value for key, value in d3.items(): a[key] = value print(a) # (逐項迴圈手動合併法) ``` ```python= a = {} a.update(d1) a.update(d2) a.update(d3) print(a) # update合併字典法 ``` ```python= d1 = {"name": "nameless", "age": 35} d2 = {"ver": 3.6, "platform": "Linux"} d3 = {"size": "50MB"} a = {**d1, **d2, **d3} print(a) # 字典解包合併寫法 ``` ```python= d1 = {"name": "nameless", "age": 35} d2 = {"ver": 3.6, "platform": "Linux"} d3 = {"size": "50MB"} a = d1 | d2 | d3 print(a) # 聯集 ```python= d1 = {"name": "nameless", "age": 35} d2 = {"ver": 3.6, "platform": "Linux"} d3 = {"size": "50MB"} a = {k: v for d in [d1, d2, d3] for k, v in d.items()} print(a) # 字典解析 ``` ### 字典安全訪問 ```python= d = { "name": "Nameless", "age": "35", } ```python= try: d["name"] d["na"] except Exception as e: print(f"error for key {e}") # 不推薦例外處理 ``` get的方法 ```python= print(d.get("name")) print(d.get("na", "unknown")) ``` 在python中有一個內置的數據類型 from collection import defaultdict defaultdict 是 Python 標準庫 collections 模組中的一個特殊字典類別,它可以幫我們自動處理不存在的key lambda: "missing" 是一個匿名函數 ```python= from collections import defaultdict d_new = defaultdict(lambda: "missing", d) print(d_new["name"]) print(d_new["na"]) ``` ## 集合 集合是一種無序、可變的資料結構,用來儲存一組唯一的元素。集合中的元素不允許重複,且沒有固定的順序。集合常用於去除重複元素,並且支援一些數學運算,例如聯集、交集和差集等。 以下是集合的主要特點: - 1.無序性(Unordered):集合中的元素是無序的,因此你不能通過索引來訪問集合中的元素。 - 2.不允許重複(No Duplicates):集合中的元素是唯一的,不允許有重複的元素。 - 3.可變性(Mutable):集合是可變的,你可以添加或刪除元素 ### 建立集合 ```python= # 創建一個集合 my_set = {1, 2, 3, 4, 5} print(my_set) # 輸出:{1, 2, 3, 4, 5} # 添加元素到集合 my_set.add(6) print(my_set) # 輸出:{1, 2, 3, 4, 5, 6} # 刪除元素從集合 my_set.remove(3) print(my_set) # 輸出:{1, 2, 4, 5, 6} # 集合的長度 print("集合長度:", len(my_set)) # 輸出:集合長度:5 ``` 有時候,會遇到一種情況,就是將list中的重複資料去除 ```python= a = ["a", "b", "a", "a", "c"] print(list(set(a))) # ['b', 'a', 'c'] print(sorted(list(set(a)))) # ['a', 'b', 'c'] ``` #### 實驗 在python中,當我宣告一個大括號裡面空的 裡面沒有任何值,它無從判斷,它會優先認為是dictionary ```python= my_set = {} print(type(my_set )) # <class 'dict'> ``` 檢查型態 ```python= fruits = {"香蕉", "蘋果", "橘子"} print(fruits) type(fruits) ``` 那集合的元素是不可重複的,如果資料重複,多於的元素會被捨去 ```python= fruits = {"香蕉", "蘋果", "橘子", "香蕉",} print(fruits) # {'香蕉', '蘋果', '橘子'} ``` 香蕉因為重複,因此只保留一筆香蕉的資料 可以使用不同類別的集合元素 ```python= fruits = {"香蕉", "蘋果", "橘子", "香蕉", 100, (1, 2)} ``` 但是不可以使用串列,字典集合,下面範例中使用串列當作集合的元素,將會報錯 ```python= fruits = {"香蕉", "蘋果", "橘子", "香蕉", 100, [1, 2]} ``` **使用set()函式建立集合** set函式的參數內容可以是字串,串列,元組,這些參數都會轉換成集合元素,例如:將串列轉換成集合 ```python= fruits = set(["香蕉", "蘋果", "橘子", "香蕉"]) print(fruits) print(type(fruits)) ``` `{'蘋果', '橘子', '香蕉'}` `<class 'set'>` 如果集合的參數是字串,集合元素將轉換成字元,同時會去除重複的字元 ```python= s = set("good day!!") print(s) print(type(s)) ``` ``{'y', '!', 'd', 'g', 'o', 'a', ' '}`` ``<class 'set'>`` ### 集合的操作 | 運算子| 意義 | |--------|--------| |& |交集 | | |聯集 | |- |差集 | |^ |對稱差集 | |== |等於 | |!= |不等於 | |in |是成員 | |not in |不是成員 | ![image](https://hackmd.io/_uploads/HJ90mcAnJe.png) ```python= set1 = {1, 2, 3, 4} set2 = {3, 4, 5, 6} ``` #### 聯集 ```python= union_set = set1.union(set2) print(union_set) # 輸出:{1, 2, 3, 4, 5, 6} ``` #### 交集 ```python= intersection_set = set1.intersection(set2) print(intersection_set) # 輸出:{3, 4} ``` #### 差集 ```python= difference_set = set1.difference(set2) print(difference_set) # 輸出:{1, 2} ``` #### 對稱差集 ```python= symmetric_difference_set = set1.symmetric_difference(set2) print(symmetric_difference_set) # 輸出:{1, 2, 5, 6} ``` #### 改寫為符號 ```python= union_set = set1 | set2 print(union_set) # 輸出:{1, 2, 3, 4, 5, 6} intersection_set = set1 & set2 print(intersection_set) # 輸出:{3, 4} difference_set = set1 - set2 print(difference_set) # 輸出:{1, 2} symmetric_difference_set = set1 ^ set2 print(symmetric_difference_set) # 輸出:{1, 2, 5, 6} ``` ## random模組 random.random()函數可以生成0~1的隨機浮點數 ```python= import random num = random.random() print(num) # 產生0-1的隨機 print(round(num, 2)) # 讓它小數點第二位 ``` 那你可能會說,我要1到5的隨機浮點數,可以這樣做 ```python= import random num = random.uniform(1,5) print(num) ``` ### random.randint() random.randint()函數可以生成一個 指定範圍內的整數,語法如下: ```python= randint(值1, 值2) ``` 如此可以產生隨機取得值1到值2之間的一個整數,包含值1和值2 ### random.randrange() randrange()函數可以生成指定範圍的整數,但不包含結尾 ```python= random.randrange(起點, 終點, 間隔): ``` ```python= import random num = random.randrange(1, 10, 2) print(num) ``` 多執行幾次,可以看到每次都產生不同的數字 ### random.choice() choice()函數可以從指定的序列中隨機選擇一個元素,語法如下: ```python= choice(序列資料) ``` 各位,請注意 random.choice() 只接受一個參數,這個參數必須是可迭代的物件 ```python= import random result = random.choice([10, 20, 30, 40, 50]) print(result) ``` random.choice() 只接受一個參數。Python 無法將這些獨立的數值組合成一個序列,這樣就會導致錯誤。正確的做法是將這些數值包裝在一個序列(例如列表或元組)中,再傳入函數中。 ## math 模組 math模組是python內建的數學運算模組,提供大量數學函數,math模組可以方便地進行數學計算,math模組中常用的函式如下: **1.求平方根** sqrt(x)函式返回x的平方根 ```python= import math ``` **2.pow(x,y)的函式返回x的y次方** ```python= import math result = math.pow(3, 3) print(result) # ``` ## 連接與字串分割 join函式可以將串列中元素連接成一個字串,語法如下: `連接字串.join(串列)` ```python= list1 = ["I", "am", "Nameless."] print(" ".join(list1)) print("|".join(list1)) # I am Nameless. 空白做結合 # I|am|Nameless. | 做結合 ``` split函式的功能與join相反,是將一個字串以指定方式分割為串列,語法如下: `字串.split([分隔字串])` ```python= str1 = "This is a book." print(str1.split(" ")) print(str1.split()) # ['This', 'is', 'a', 'book.'] # ['This', 'is', 'a', 'book.'] ``` 分隔字串可有可無,若未傳入分隔字串,預設為1個空白字元 例如說:我以下有yyy,那我以它做分隔 ```python= str2= "Thisyyyisyyyayyybook." print(str2.split("yyy")) # ['This', 'is', 'a', 'book.'] ``` 就可以看到結果與上述相同 ### 檢查起始或結束字串 **startswith** startswith函式是檢查字串是否以指定字串開頭 語法如下: ```python= 字串.startswith(起始字串) ``` 如果字串式以[起始字串]開頭,則回傳true 否則回傳false ```python= str3 = "email:python.com.tw" print(str3.startswith("email") # True print(str3.startswith("tw")) # False ``` endswith函式的功能與starstwith類似 差異在endswith函式檢查的是字串是否以指定結束字串,語法如下 ```python= 字串.endswith(起始字串) ``` 如果字串式以[結尾字串]結束,則回傳true 否則回傳false ```python= str3 = "email:python.com.tw" print(str3.endswith("tw")) # True print(str3.endswith("email")) # False ``` ### 範例練習 **如果是http://或者 https:// 開頭 則輸出:("輸入網址格式正確") 否則輸出:("輸入網址格式錯誤")** 結果如下: ![image](https://hackmd.io/_uploads/HkMHvmXKkl.png) ![image](https://hackmd.io/_uploads/r12UPQQYJg.png) <details> <summary>點此展開程式碼</summary> web_str = input("請輸入網址: ") if web_str.startswith("http://") or web_str.startswith("https://"): print("輸入網址格式正確") else: print("輸入網址格式錯誤") </details> http://www.python.com.tw ## 指數,商數,餘數及四捨六入 ### pow函式 pow函式不但可以做指數運算,還可以計算餘數,語法如下: ```python= pow(x, y[, z]) ``` 如果只有x及y參數,傳回值為x的y次方,例如: ```python= pow(3 ,4) # 81 ``` 若有z參數,意義為x的y次方除以z的餘數 ```python= pow(3 ,4 ,5) # 1 ``` 3的4次方為81,81除以5為16剩餘1 如果傳入三個參數 x, y, z,則會先計算 x 的 y 次方, 再對 z 取餘數(也就是求 (x ** y) % z 的結果) ### divmod函式 **divmod函式會同時回傳商數與餘數** divmod() 的返回結果是元組(tuple) 語法如下: ```python= divmod(x, y) ``` ```python= result = divmod(11, 3) print(result) # (3, 2) ``` 商數為3, 餘數為2 ```python= print(result[0]) print(result[1]) ``` ### round函式 round函式以四捨六入的方法取得x近似值,語法如下 ```python= round(x [, y]) ``` ```python= print(round(3.4)) # 3 print(round(3.6)) # 4 print(round(3.5)) # 4 print(round(2.5)) # 2 ``` 四捨六入是4以下(包含4)的數字捨去,6以上(包含6)以上的數字進位 那5呢?就必須視前一個位數而定,前一位是偶數就將5捨去 前一位是奇數,就將其進位 換個例子,現在加入y參數 ```python= print(round(3.95, 1)) # 4 print(round(3.855, 2)) # 3.85 print(round(3.845, 2)) # 3.85 ``` 說明: 偶數四捨五入,小數點後三位是5 那前面的的小數點第2位是奇數,不進位所以是3.85 最後一個3.845,第2位是偶數,所以會進位 3.85 #### 綜合驗收 **輸入人數與麵包總數,將麵包平均分給學生 每個人分到的麵包必須是相同的 1.計算麵包平均分配到多少學生 2.計算剩餘麵包數量 假設人數為12人,麵包總數為:100,會剩下4個麵包** <details> <summary>點此展開程式碼</summary> ```python= person = int(input()) bread = int(input()) result= divmod(bread, person) print(f'分配: {result[0]} 人') print(f'剩餘: {result[1]} 個麵包') ``` </details> 結果如下: ![image](https://hackmd.io/_uploads/SJ89hjeKyx.png) # 函式(Function) 函式是一個可以重複使用的程式區塊,通常用來執行特定的任務或操作。使用函式能讓程式碼結構變得更簡潔,且易於理解和維護。 ### 定義一個簡單的函式 首先,我們來定義一個基本的函式,這個函式會輸出 "Hello World!": ```python= def greet(): print("Hello World!!!") ``` 接著,我們可以呼叫這個函式: ```python= greet() ``` 讓函式根據參數進行動作 如果希望函式能根據不同的呼叫者輸出不同的訊息,可以讓函式接受一個參數: ```python= def greet(name): print(f"Hello, {name}!!!") ``` 然後可以這樣呼叫: ```python= greet("Tom") # 輸出:Hello, Tom!!! greet("Sam") # 輸出:Hello, Sam!!! ``` 函式回傳運算結果 有時候,我們希望函式進行一些計算並回傳結果,可以使用 return: ```python= def add(a, b): return a + b ``` ```python= print(add(1, 2)) # 輸出:3 ``` 位置與名稱傳遞參數 在 Python 中,傳遞參數有兩種方式:依照位置或依照名稱傳入。這兩種方式可以混合使用,但要注意位置參數必須在名稱參數之前傳入: ```python= print(add(1, 2)) # 依位置傳參數 print(add(b=2, a=1)) # 依名稱傳參數 ``` 混合位置參數與名稱參數 以下是合法與不合法的呼叫範例: ```python= add(1, 2) # 合法 add(b=2, a=1) # 合法 add(1, b=2) # 合法 add(a=1, 2) # 不合法,名稱參數不能在位置參數前 add(1, a=1) # 不合法,名稱參數不能指定已經傳入的參數 ``` 回傳多個值 有時我們希望函式回傳多個結果,可以直接回傳一個元組: ```python= def add_and_subtract(a, b): return a + b, a - b ``` 可以這樣使用: ```python= result = add_and_subtract(1, 2) print(result) # 輸出:(3, -1) sum_result, diff_result = add_and_subtract(1, 2) # 拆解元組 print(sum_result, diff_result) # 輸出:3 -1 ``` 提前退出函式 有時候,當某些條件成立時,我們希望函式提前退出並不執行後續的程式碼,可以使用 return: ```python= def shop(money): if money <= 0: return print("購物中...") ``` 如果傳入 money <= 0,則函式會提前返回,後面的程式不會被執行。 預設參數值 如果希望函式的某些參數具有預設值,這樣在呼叫時如果未傳入對應的參數,會使用預設值: ```python= def greet(name="World"): print(f"Hello, {name}!!!") ``` 呼叫函式時: ```python= greet() # 輸出:Hello, World!!! greet("Ruby") # 輸出:Hello, Ruby!!! ``` 接受不定數量的參數 若希望函式接受不確定數量的參數,可以使用 *args 和 **kwargs: ```python= def func(*args, **kwargs): print(args, kwargs) *args:接收依照位置傳遞的多個參數,並將它們組成元組。 **kwargs:接收依照名稱傳遞的多個參數,並將它們組成字典。 ``` 範例: ```python= func() # 輸出:() {} func(1, 2, 3) # 輸出:(1, 2, 3) {} func(a=1, b=2, c=3) # 輸出:() {'a': 1, 'b': 2, 'c': 3} func(1, 2, x=3) # 輸出:(1, 2) {'x': 3} ``` ## 匿名函式(lambda) 如果這個函式是一次性的,不需要重複使用,也不需要取名字,就可以用 lambda。 一般我們去定義一個名為g的函數 接收一個參數x,函數內部進行運算 並使用return回傳結果 ```python= def g(x): return x + 1 print(g(1)) # 結果為2 ``` 再舉一個簡單的例子 ```python= g1 = lambda x, y: x + 2 * y print(g1(1, 2)) # 5 ``` 一行打 ```python= print((lambda x, y: x + 2 * y)(1, 2)) ``` 這裡有一個包含三個元組(tuple)的列表(list) 我要做排序 #### 函式方法對元素做排序 ```python= data = [(1, 2), (3, 1), (5, 4)] def get_second_element(x): return x[1] sorted_data = sorted(data, key=get_second_element, reverse=False) print(sorted_data) ``` #### lambda對元素做排序 ```python= data = [(1, 2), (3, 1), (5, 4)] sorted_data = sorted(data, key=lambda x: x[1], reverse=False) print(sorted_data) # [(3, 1), (1, 2), (5, 8)] ``` ```python= data2 = ["Nameless", "Python", "Git", "linux", "apple"] print(sorted(data2, key=lambda x: x.lower())) # ['apple', 'Git', 'linux', 'Nameless', 'Python'] ``` #### 函式參數的默認值 透過一個簡單的類別來介紹什麼是「函式參數的默認值」。 順便幫大家複習一下類別 首先,先定義一個名為 Hi的類別 class Hi: 它有一個方法稱為say,第一個放這個類別的實例本身(self, name,greetings): name和gretting 是兩個參數 print(f'{name}, {greetings}') 把 name 和 greetings 放到字串中並印出來。 hi = Hi() # 調用它實例化的對象 hi.say(name='Nameless',greetings='hello') 裡面有兩個參數,我們執行一下,這應該沒有問題 ```python= class Hi: def say(self, name, greetings=hi): print(f"{name}, {greetings}") hi = Hi() hi.say(name="Nameless", greetings="Hello World") ``` # TQC-python ## 第一版 ### 701-710 #### 703 ![image](https://hackmd.io/_uploads/S1U8lYiT1x.png) ![image](https://hackmd.io/_uploads/HJUPgYiTkl.png) 海象運算子(python ver_3.8) 解法 <details> <summary>點此展開程式碼</summary> ```python words = () while (word := input()) != "end": words += (word,) print(words) print(words[:3]) print(words[-3:]) ``` </details> ## 檔案讀取與寫入 ### 檔案讀取 在 Python 中,您可以使用內建的 open() 函式來開啟檔案,並指定不同的模式(如讀取模式、寫入模式、附加模式等)來進行相應的操作。 使用 open() 函式以讀取模式('r')開啟檔案,然後使用 read() 方法讀取檔案內容: ```python= file_path = "example.txt" file = open(file_path, "r") content = file.read() print(content) file.close() ``` 在此範例中,我們以讀取模式 'r' 開啟名為 example.txt 的檔案,使用 read() 方法取得檔案內容並儲存至變數 content,接著輸出內容,最後使用 close() 關閉檔案。 只是每次都要關檔有點麻煩,而且有可能因為還沒執行到關檔就發生錯誤,所以沒有正確關閉檔案。為了解決這些問題我們將上方範例改寫 ```python= file_path = "example.txt" with open(file_path, "r") as file: content = file.read() print(content) ``` 在此範例中,with 陳述式會在程式碼區塊結束時自動關閉檔案,無需手動呼叫 close()。 若需逐行讀取檔案內容,特別是在處理大型檔案時,以下範例示範如何逐行讀取並處理每一行 ```python= with open(file_path, "r") as file: for line in file: print(line.strip()) # 刪除每行末尾的換行符號 ``` 除了 "r" 模式外,open() 函式還支援其他模式,如 "w"(寫入模式)、"a"(附加模式) 等。如果在寫入或附加模式下,如果指定的檔案不存在,Python 會自動創建該檔案。 ## 寫入檔案 ```python= with open("output.txt", "w") as file: file.write("這是寫入的內容\n") ``` ### 附加到檔案 ```python= with open("output.txt", "a") as file: file.write("這是附加的內容\n") ``` 上方提到的模式都只能進行單一行為操作,如果有需要同時寫入跟讀取可以直接在現有模式後方加上 + 即可。 下方是對 r、r+、w、w+、a 和 a+ 模式進行比較的表格: | 模式 | 讀取 | 寫入 | 清空檔案 | 檔案不存在時的行為 | |-------|------|------|----------|---------------------| | `r` | 可 | 不可 | 不會 | 錯誤 | | `r+` | 可 | 可 | 不會 | 錯誤 | | `w` | 不可 | 可 | 會 | 創建新檔案 | | `w+` | 可 | 可 | 會 | 創建新檔案 | | `a` | 不可 | 可 | 不會 | 創建新檔案 | | `a+` | 可 | 可 | 不會 | 創建新檔案 | # Tkinter模組 ## 視窗區塊 當我們元件數量增加時.許多元件 都集中再主視窗,看起來會很亂 視窗區塊也是一個容器,可以將元件分類置不同區塊中 ![image](https://hackmd.io/_uploads/ry_GPqiv1l.png) * 建立視窗區塊的語法為: ```python= 視窗區塊變數 = tk.Frame(容器名稱, 參數1, 參數2....) ``` 在主視窗 win 中創建一個名為 frame1 的視窗區塊,可以這樣寫: ```pytohn= frame1 = tk.Frame(win) ``` 標籤是使用 tk.Label 類別創建的。通常,標籤顯示的文字或圖片會在同時使用配置選項時指定: ```python= label = tk.Label(parent, text='Full name:') ``` 參考文件 Label * https://tkdocs.com/tutorial/widgets.html#label ```python= entry = tk.Entry(parent, textvariable=username) ``` 參考文件 Entry https://tkdocs.com/tutorial/widgets.html#entry * 關於.grid(),標籤與文字框可以理解為位置 | | column 0| column 1 | |--------|--------|--------| | row0 |label1 |entry1 | * 這讓視窗持續顯示,並等候用戶操作 ```python= win.mainloop() ``` <details> <summary>點此展開程式碼</summary> ```python= import tkinter as tk win = tk.Tk() win.title("標題") # 第一種視窗區塊 frame1 = tk.Frame(win) frame1.pack() label1 = tk.Label(frame1, text="文字標籤", font=("Arial", 16)) entry1 = tk.Entry(frame1) label1.grid(row=0, column=0) entry1.grid(row=0, column=1) # 第二種視窗區塊 frame2 = tk.Frame(win) frame2.pack() button1 = tk.Button(frame2, text="確定", font=("Arial", 16), padx=20) button2 = tk.Button(frame2, text="取消", font=("Arial", 16), padx=20) button1.grid(row=0, column=0) button2.grid(row=0, column=1) win.mainloop() ``` </details> *執行結果如下:* ![image](https://hackmd.io/_uploads/H1T-P9ow1e.png) # 數據資料的儲存與讀取 ## csv資料的儲存與讀取 常聽到CSV檔案,那它的全名是什麼? Comma(ˈkämə)-separated values 就是以逗號分隔值的資料格式並以純文字的方式儲存檔案 csv檔案是純文字檔案,編輯時可以直接使用文字編輯器 例如說:windows內建的記事本,但閱讀上比較不方便 大多數的人會用EXCEL來使用csv檔案 csv檔是許多資料編輯,讀取,儲存時很喜歡的格式 因為是純文檔案,操作方便且輕量 python,可以使用csv模組輕鬆來存取.csv檔案 ### csv檔案儲存 可以使用串列或字典資料類型,將資料寫入csv檔案 而串列的寫入方式 **1.csv寫入物件.writerow():寫入一維串列** __2.csv寫入物件.writerows():寫入二維串列__ ```python= import csv # 開啟輸出的csv檔案 with open("我要建立的檔名.csv","寫入w",newline="") as 檔案: # 記得冒號和縮排 , # 建立csv檔寫入物件 變數存放 = csv.writer(檔案) # 再拿變數去寫入一維串列 變數.writerow([.., ..., ...]) ``` w:表示如果檔案已經存在會覆蓋它。如果檔案不存在則會創建新檔案。 newline="": 這個參數告訴 Python 不要自動處理行尾的換行符號 <font size="5">將一維串列資料寫入csv檔案</font> 利用csv.writer方法,可以建立一個寫入csv檔案的物件,再利用writerow方法就可以寫入一維的串列資料 <details> <summary>點此展開程式碼</summary> ```python= import csv with open("test01.csv", "w", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerow(["姓名", "身高", "體重"]) writer.writerow(["Nameless", "173", "76"]) writer.writerow(["Joanna", "164", "76"]) ``` </details> 製作結果如下: ![image](https://hackmd.io/_uploads/BJFKZAY_1x.png) <font size="5">將二維串列資料寫入csv檔案</font> 除了一維的串列資料 也可以用writerows方法寫入二維的串列資料 ```python= import csv csv_table = [ ["姓名", "身高", "體重"], ["Nameless", "173", "76"], ["Joanna", "164", "76"], ] with open("test02.csv", "w", newline="") as csvfile: writer = csv.writer(csvfile) writer.writerows(csv_table) ``` </details> ### 將字典資料寫入csv檔案 可以使用csv.DictWriter直接將字典類型的資料 寫入csv檔案中 ```python= import csv with open('names.csv', 'w', newline='') as csvfile: fieldnames = ['first_name', 'last_name'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'}) writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'}) writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'}) ``` writer = csv.DictWriter(csvfile, fieldnames=fieldnames) 它的fieldnames是指欄位名稱 它的csv.DictWriter接收兩個參數,前面csvfile:將csvfile寫入 後面的fieldnames:是指欄位名稱 writer.writeheader(): 是csv.DictWriter 物件中的一個方法, 它的作用是將 fieldnames 中定義的欄位名稱寫入 CSV 檔案的第一行,也就是標題行。 <details> <summary>點此展開程式碼</summary> ```python= import csv filednames = ["姓名", "身高", "體重"] with open("test03.csv", "w", newline="") as csvfile: writer = csv.DictWriter(csvfile, filednames) writer.writeheader() writer.writerow({"姓名": "Nameless", "身高": 173, "體重": 76}) writer.writerow({"姓名": "Joanna", "身高": 164, "體重": 76}) ``` </details> 結果如下: ![image](https://hackmd.io/_uploads/Hy9jnl5uyl.png) 官方文件參考: **https://docs.python.org/3/library/csv.html** # 猜數字遊戲 讓電腦隨機選擇一個介於 1 和 100 之間的數字(包含 1 和 100)。 接著,提示使用者猜測一個數字。系統會檢查使用者輸入的數字是否有效,並確認其在合法範圍內。 如果使用者猜的數字大於電腦選擇的數字,範圍會調整為 1 到使用者猜的數字減 1。 如果使用者猜的數字小於電腦的數字,範圍會調整為使用者猜的數字加 1 到 100。 這個過程會持續進行,直到使用者猜中正確的數字為止。 ```python= """ 讓電腦隨機選擇一個介於 1 和 100 之間的數字(包含 1 和 100)。 接著,提示使用者猜測一個數字。系統會檢查使用者輸入的數字是否有效,並確認其在合法範圍內。 如果使用者猜的數字大於電腦選擇的數字,範圍會調整為 1 到使用者猜的數字減 1。 如果使用者猜的數字小於電腦的數字,範圍會調整為使用者猜的數字加 1 到 100。 這個過程會持續進行,直到使用者猜中正確的數字為止。 """ import random def guess_number_game(): start = 0 end = 100 guess_count = 0 ans = random.randint(start, end) print(ans) while True: user_input = input(f"請輸入一個 {start} ~ {end}的數字: ") try: user_input = int(user_input) except ValueError: print("請輸入一個整數") continue if not (start <= user_input <= end): print(f"請輸入介於 {start} 與 {end} 之間的數字") continue guess_count += 1 if user_input == ans: print(f"恭喜答對,共猜了{guess_count}次") break if user_input < ans: start = user_input + 1 if user_input > ans: end = user_input - 1 guess_number_game() ``` ## 解法二 ```python= import random class GuessNumberGame: def __init__(self): self.start = 1 self.end = 100 self.guess_count = 0 self.ans = random.randint(self.start, self.end) def user_input(self): return int(input(f"請輸入 {self.start} ~ {self.end} 的數字: ")) def play_game(self): print(f"目前的答案為: {self.ans}") while True: user_input = self.user_input() if user_input == self.ans: print(f"恭喜答對,共猜了{self.guess_count}") break self.guess_count += 1 if user_input < self.ans: self.start = user_input + 1 if user_input > self.ans: self.end = user_input - 1 game = GuessNumberGame() game.play_game() ``` # 錯誤處理 錯誤處理是用來處理程式在執行過程中可能出現的錯誤或異常情況的一種方法。透過錯誤處理,我們可以防止程式因錯誤而中斷,並提供更穩定的用戶體驗。 在 Python 中,try 和 except 語句用來實現錯誤處理。這些語句讓你能夠捕獲並處理異常,從而確保程式在遇到錯誤時能繼續運行,而不會停止。 ```python= try: n = 100 / int(input()) except ValueError: print("請輸入數字") except ZeroDivisionError: print("請勿除以0") except Exception as e: print("發生未知的錯誤", e, type(e)) print("OK") ``` ```python= try: # 嘗試執行可能引發異常的程式碼 result = 10 / 0 # 這個操作會引發 ZeroDivisionError except ZeroDivisionError: # 在捕獲到指定類型的異常時執行這裡的程式碼 print("發生了除以零的錯誤") ``` 在這個範例中,我們使用 try 塊來包裹可能引發異常的程式碼。如果 try 塊中的程式碼引發了指定的異常(例如這裡的 ZeroDivisionError),程式會跳轉到對應的 except 塊來處理該異常。 你可以使用多個 except 塊來處理不同類型的異常,此外,還可以使用 else 塊來處理在沒有異常發生時執行的程式碼,並利用 finally 塊來執行無論是否發生異常都需要執行的清理操作。 ```python= try: result = 10 / 0 except ZeroDivisionError: print("發生了除以零的錯誤") except ArithmeticError: print("發生了算術錯誤") else: print("沒有發生異常") finally: print("無論是否有異常,都執行此處的程式碼") ``` 通過適當的錯誤處理,你可以更好地控制程式的執行,並在發生異常時提供有用的訊息,從而提高程式的可靠性。 ```python= try: n = 100 / int(input()) except ValueError: print("請輸入數字") except ZeroDivisionError: print("請勿除以0") # else: # print(n) # finally: # # 無論是否發生例外都會執行 # print("這是finally區塊") print("OK") ``` # 類別與物件 ## 類別與物件 完整的應用程式通常由許多類別組成。Python是一種物件導向的程式語言,可以使用類別來定義物件的結構和行為。 在 Python 中,使用 class 關鍵字來定義一個類別。類別是一個藍圖或模板,用來創建物件(也稱為實例)。根據這些類別,可以建立不同的物件,並且每個物件都可以擁有獨立的屬性和方法。 類別的命名:按照 Python 的命名慣例,類別名稱的第一個字母通常會使用大寫字母(這是一種稱為「駝峰式命名法」的命名規範),例如:MyClass 或 Car。 ```python= class 類別名稱(): 定義類別 定義屬性 定義方法 建立物件 # 以類別名稱即可建立物件(object) 物件 = 類別() # 然後以物件執行其屬性和方法 物件.屬性 物件.方法() ``` 類別中通常會建立屬性和方法,提供物件使用,類別中的屬性 其實就是一般的變數,方法則是指函式,但在類別中不會以變數 和函式稱呼,而是稱為屬性與方法,我這邊舉個例子 ```python= class Animal: name = "小鳥" def sing(self): print("很愛唱歌") bird = Animal() bird.name bird.sing() ``` 執行結果: ![image](https://hackmd.io/_uploads/BkpDnYDvkg.png) ## 類別的建構式 建立類別時,必須對類別初始化,因此必須建立一個特殊的方法, __init__,這個初始化的方法稱為建構式 建立建構式的語法: ```python= class 類別(): def __init__(self[參數1, 參數2....]): ``` 建構式必須使用__init__()函式,參數self是必須的,同時要放在最前面 其餘的參數式可選擇性的,如此在類別中就可以用self.屬性,self.方法執行類別的屬性與方法 ```python= class Animal: def __init__(self, name): self.name = name def sing(self): print(f"{self.name}, 很愛唱歌") bird = Animal("鴿子") print(bird.name) bird.sing() # def __init__(self): # pass # 預設的建構式,什麼都不做 ``` ![image](https://hackmd.io/_uploads/B1b0hTwP1g.png) 結論:每個物件有自己的初始化屬性(如物件的名字)。 不使用 __init__ 時,屬性是固定的,所有物件共享同一屬性值。 ## 多重繼承 子類別也可以繼承多個父類別,語法如下: class 子類別名稱(父類別1, 父類別2, 父類別n): 如果父類別擁有相同名稱的屬性或方法時,就要注意搜尋的順序 是從子類別開始,接著是同一階層父類別由左至右搜尋 ```python= class Father: def say(self): print("yes") class Mother: def say(self): print("no") class Child(Father, Mother): pass child = Child() child.say() ``` ## 計算面積 定義 Rectangle,Triangle,兩個類別,父類別Rectangle 定義共同屬性width,height,和area()方法計算矩形面積 Triangle子類別繼承Rectangle類別並增加一個計算三角形 面積的方法area2() ![image](https://hackmd.io/_uploads/SJeO2RHvyg.png) <details> <summary>程式碼: class_area.py (點此展開)</summary> ```python= class Rectangle: def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height class Triangle(Rectangle): def area2(self): return (self.width * self.height) / 2 triangle = Triangle(10, 5) print(f"三角形的面積為: {triangle.area2()}") print(f"矩形的面積為: {triangle.area()}") ``` </details> 說明: 當創建 triangle = Triangle(10, 5) 物件時, Triangle 類別會初始化 weight 和 height 屬性, 並且可以使用來自父類別 Rectangle 的 area() 方法來計算矩形的面積。triangle.area2() 計算的是三角形的面積, 使用的是子類別 Triangle 的 area2() 方法。 ## class複習 ```python= class Student: def __init__(self, name, age, sch, dept, add): self.name = name self.age = age self.sch = sch self.dept = dept self.add = add def say_hello(self): print("Hello") std = Student("xxx", 30, "sc", "py", "tpe") print(std.name) std.say_hello() # xxx # Hello ``` 各位注意,明明有五個參數,但我只給四個,結果沒有報錯 原因是右下角type checking沒有選擇standard ![image](https://hackmd.io/_uploads/HJg1cjjuJx.png) # 建立自己的模組 一個較大型專案,程式是由許多類別與函式組成,為了程式分工與維護 可以適度的將程式分割成許多模組 再匯入並呼叫這些模組 ## 準備工作 下列程式包含計算兩數相加,兩數相減的兩個函式,可以直接呼叫add,sub函式來執行兩數相加,相減的運算,檔名:**module_1.py** ```python= def add(n1, n2): return n1 + n2 def sub(n1, n2): return n1 - n2 print(add(7, 3)) print(sub(7, 3)) ``` 有時為了程式的分工和維護,我們會將程式分割成模組 那我再建立一個獨立模組名: <b>calculate.py</b> ```python= def add(n1, n2): return n1 + n2 def sub(n1, n2): return n1 - n2 ``` ## import模組名稱 那完成模組之後我要匯入自己的模組 ```python= import 模組名稱 ``` 例如: 匯入calculate模組 ```python= import calculate ``` 這種方式呼叫函式時,必須加上模組名稱,語法: ```python= calculate.函式名稱 ``` **module_2.py** ```python= import calculate print(calculate.add(7, 3)) # 10 print(calculate.sub(7, 3)) # 4 ``` <b>功能分離:</b> 你可以將不同的程式邏輯分開,讓每個檔案專注於做某一個工作。 <b>重複利用:</b> 如果在其他地方也需要進行加減法運算,只需要導入 calculate.py, 就可以直接使用裡面的 add 和 sub 函式,而不用每次都重寫相同的程式碼。 ## 匯入模組內函式 每次使用模組內的函式都要輸入模組名稱非常麻煩,下面import的方式可以改善情況,語法 ```python= from 模組 import 函式名稱1[,函式名稱2.......] ``` 這種方式呼叫函式,可以省略模組名稱,直接以函式名稱呼叫 **檔名:module_3.py** ```python= from calculate import add, sub print(add(7, 3)) # 10 print(sub(7, 3)) # 4 ``` 各位我換一個例子,建立**module_4.py** 我故意不import sub,來看一下會有什麼樣的結果 ```python= from calculate import add print(add(7, 3)) print(sub(7, 3)) ``` 它會出現,name 'sub' is not defined. 這是因為只有被列出的函式會被導入,其他函式就無法使用。 ## 匯入模組內所有函式 建立**module_5.py** ```python= from calculate import * print(add(7, 3)) print(sub(7, 3)) ``` * 表示全部的意思,這個方法比較方便 但這樣做比較不好,原因是因為每一個模組 都有眾多函式,如果我有兩個模組都導入add函式 那後面導入的add,就會覆蓋前面的 這什麼意思呢?我解釋一下喔! 例如我去新增一個**calculate1.py** 故意去修改add的函式 ```python= def add(n1, n2): return n1 + n2 * 2 def sub(n1, n2): return n1 - n2 ``` 再回到**module_5.py** ```python= from calculate import * from calculate1 import * print(add(7, 3)) # 13 ``` 會得到13,這不是我們要的結果 可以看到後面導入的add函式,就會覆蓋前面的函式 ## 使用as指定函式別名 如果不同模組中的函式名稱相同,或是函式名稱太長 我們可以自行指定別名 語法如下: ```python= from 模組名稱 import 函式名稱 as 函式別名 ``` 建立 **module_6.py** 這個時候,我們就可以函式別名呼叫 ```python= from calculate import add as a from calculate1 import add as a1 print(a(7, 3)) # 10 print(a1(7, 3)) # 13 ``` ## 使用as指定模組別名 這裡建立好**module_7.py** 那各位可能會認為說,不是函式名稱太長 而是模組名稱calculate太長,我們可以這樣做 ```python= import 模組名稱 as 別名 ``` 如此一來,使用函式時使用[別名.函式名稱],就可以避免較長模組名稱 ```python= import calculate as cal print(cal.add(7, 3)) print(cal.sub(7, 3)) ``` # numpy ## 建立一維陣列 ```python= import numpy as np np1 = np.array([1, 2, 3, 4]) np2 = np.array([5, 6, 7, 8]) print(np1) print(np2) print(type(np1), type(np2)) ``` ## numpy統計函數 | 函數 |運算| 函數 |運算| |--------|--------|--------|--------| | sum |總和 | prod |乘積 | | mean |平均值 | std |標準差 | | max |最大值 | var |變異數 | | min |最小值 | cumsum |陣列元素累加 | | median |中位數 | cumprod |陣列元素累乘 | 影片名稱:numpy統計函數 ```python= import numpy as np seed = 0 np1 = np.random.RandomState(seed).randint(1, 51, 12).reshape(3, 4) print(np1) ``` ## numpy 數組 ```python= import numpy as np arr1 = np.array([1, 2, 3]) arr2 = np.array([[1, 2, 3], [4, 5, 6]]) ``` 創建一個數組,最直接的方法就是透過 numpy的array方法把列表轉為數組 最簡單判斷的方式,是看有幾個方括號,就可以判斷有幾維數組 ```python= arr1.ndim # 1 ``` 而shape會返回一個元組,表示各個元素的個數 ```python= arr1.shape #(3,) 表示一個維度有三個元素 ``` 我們要去看他的類型,可以用dtype,它是int32(int64) ```python= arr1.dtype # int開頭說明類型是整數 # Out[26]: dtype('int32') ``` 在numpy裡面,也有方法稱為arange 表示針對array的range方法 ```python= np.arange(起點,終點,間隔) np.arange(1,10,2) # Out[25]: array([1, 3, 5, 7, 9]) ``` # 網頁資料擷取與分析 如果去網路抓資料,會用到requests套件 對伺服器提出request要求,它會回應一個response import requests 現在我想把一個網頁抓出來 可以這樣做,將網址複製到url ## request套件,擷取新聞網頁原始碼 ```python= import requests url = "https://news.google.com/home" setting = { "hl": "zh-TW", "gl": "TW", "ceid": "TW:zh-Hant", } resp = requests.get(url, params=setting) with open("gogole_news.html", "w", encoding="utf-8") as file: file.write(resp.text) ``` 結果如下: ![image](https://hackmd.io/_uploads/r1uNXq21ge.png) 在做資料擷取的時候不可能每次都很順利 這公開資訊都給我們看了,為什麼不能用程式去抓? 想看看,電腦一秒鐘可以執行百萬行指令 server不可能專程服務我一個人而已 所以面對不同的網站,有不同的方法,各位懂我意思嗎? ### 抓取需要認證從瀏覽器過來抓取的網頁資料 ```python= import requests url = "https://irs.thsrc.com.tw/IMINT/?locale=tw" ua = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36" } resp = requests.get(url, headers=ua) with open("HRS.html", "w", encoding="utf-8") as file: file.write(resp.text) ``` **作者:非本科系學程式找工作**