顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

2024年6月2日 星期日

[Python] threading

在閱讀關於 python multi-thread(多執行緒)、multi-process(多行程)及GIL的相關文章時,突然想到在公司寫的一個 script。 這 script需要使用同個 api發送不同參數的HTTP request,一開始的寫法是使用 for loop來執行,等到 request結束,再執行下一個。

由於每個 request需要幾十秒才會完成,所以整個 sciprt跑完就要花費好幾分鐘。如果能改寫成 使用 multi-thread的方式來發送 request,就能省下大量的時間。因為 GIL的關係,同時間只會 有一個 thread在執行,但以這 case來說已經很夠用了。

以下是要修改的 sample code,使用 for loop來執行 20次的 request:

import requests

def do_request(url):
    response = requests.get(url)
    print(response.status_code)
    return response

if __name__ == '__main__':
    for i in range(0, 20):
        ret = do_request("https://api.github.com")
        print (ret.json())

使用 python threading來改寫:

import requests
import threading

def do_request(url):
    response = requests.get(url)
    print(response.status_code)
    return response

if __name__ == '__main__':
    thread_list = []
    for i in range(0, 20):
        t = threading.Thread(target=do_request, args=("https://api.github.com",))
        thread_list.append(t)
        t.start()

    for t in thread_list:
        t.join()


宣告 Thread


t = threading.Thread(target=do_request, args=("https://api.github.com",))

建立一個 Thread物件,將要使用 threads來執行的 function傳入 target,並把 target所需要的引數以 tuple的形式傳入 args。


啟動 Thread


t.start()

透過呼叫 start來啟動此 thread。


等待 Thread執行完成


t.join()

使用 join來等待此 thread結束。這裡使用 for loop來等待所有的 thread結束。 若沒有使用 join,thread可能會在主程式後才執行完成。


獲得 Thread的返回值

上面的程式碼雖然可以讓函式使用 thread的方式執行,卻沒辦法得到函式的返回值。其中一個解法是將函式改寫,使其將返回值存到 list中。

import requests
import threading

def do_request(url, index, response_list):
    response = requests.get(url)
    print(response.status_code)
    response_list[index] = response

if __name__ == '__main__':
    thread_list = []
    response_list = [None] * len(range(0, 20))
    for i in range(0, 20):
        t = threading.Thread(target=do_request, args=("https://api.github.com", i, response_list))
        thread_list.append(t)
        t.start()

    for t in thread_list:
        t.join()

    print(response_list)

參考資料:
https://docs.python.org/zh-tw/3/library/threading.html
https://realpython.com/intro-to-python-threading/


2022年11月25日 星期五

[scikit-learn] datasets

最近開始在上 Coursera台大林軒田的 Machine Learning的課程,第二周的內容重點是關於 PLA
(Perceptron Learning Algorithm),於是就想實作關於 PLA的程式碼。

首先是要有一組線性可分的資料,但要手動產生線性可分資料過於麻煩,而 scikit-learn提供
datasets 這個為機器學習使用者所用的資料集合。

以 iris plant dataset為例,其提供了鳶尾花的植物特徵資料:

https://scikit-learn.org/stable/datasets/toy_dataset.html
  • 花萼長度 (sepal length in cm)
  • 花萼寬度 (sepal width in cm)
  • 花瓣長度 (petal length in cm)
  • 花瓣寬度 (petal width in cm)
  • Class:Setosa、Versicolour及Virginica

三個品種的鳶尾花各50組,總共150組資料。透過 load_iris來獲得:

https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html

參考scikit-learn提供的範例The Iris Dataset來看其資料分布的情形。可以用來練習線性可分
的情況,也能練習在線性不可分下中使用 Pocket Algorithm。

用 matplotlib畫出其資料分布圖:


2022年10月29日 星期六

[Python] Decorator 裝飾器 (2) - wraps

上篇文章:
[Python] Decorator 裝飾器

在使用 decorator時,會使得原本被包裹的 function 的 attribute資料遺失。

import time

def measuretime(func):

    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    while n > 0:
        n -= 1

if __name__ == '__main__':
    print (count_down.__name__)
    print (count_down.__doc__)

Output:

wrapper
None

可使用 functools的 decorator wraps來避免這種情況:

import time
from functools import wraps

def measuretime(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    while n > 0:
        n -= 1

if __name__ == '__main__':
    print (count_down.__name__)
    print (count_down.__doc__)

Output:

count_down
Counts down from n

Unwrapping

wraps提供了另一個有用的功能,可以使已經套用過 decorator的 function回復成套用前的
function。透過 __wrapped__這個屬性來使用原本的 function。

import time
from functools import wraps

def measuretime(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    '''Counts down from n'''
    print (f'Counts down from {n}')
    while n > 0:
        n -= 1

if __name__ == '__main__':
    count_down(500000)
    org_count_down = count_down.__wrapped__
    org_count_down(500000)

Output:

Counts down from 500000
count_down 0.021966218948364258
Counts down from 500000

2022年10月23日 星期日

[Python] Decorator 裝飾器 (1)

最近發現自己在 Python上的技巧需要提升,雖然以前就知道 Decorator的概念,但我在
實際應用上很少使用,趁此機會來重新理解下。

Decorator簡單來說,是一種 function,並以另一個 function作為輸入,用來擴充輸入
function的功能。

以下面程式碼為例:

def hello_alice(hello_func):
    hello_func("Alice")

def say_hello(name):
    print (f"Hello {name}")

if __name__ == '__main__':
    hello_alice(say_hello)

Output:

Hello Alice

這裡 hello_alice使用 say_hello當作參數傳入, hello_alice就是作為 say_hello的
decorator。


Syntactic Sugar

通常 decorator會使用更簡潔的語法糖 "@"包裝,使用上面的範例修改:

def hello_alice(hello_func):
    hello_func("Alice")

@hello_alice
def say_hello(name):
    print (f"Hello {name}")

if __name__ == '__main__':
    say_hello

Output:

Hello Alice

@hello_alice代表將 say_hello當作參數傳入 hello_alice function。


Inner Functions

Python的 function也能夠在另一個 function中被定義,稱為 inner function。inner function可以
讓 decorator的使用更加靈活:

def greet(func):

    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result

    return wrapper

@greet
def say_hello(name):
    print(f"Hello {name}")

if __name__ == '__main__':
    say_hello("Alice")
    say_hello("Bob")

Output:

Hello Alice
Hello Bob

其中 wrapper就是作為 decorator @greet的 inner function。 並且會使用 *args與 **kwargs來接收參數。


Example - Measure Time

一個 decorator經典的範例是用於測量 function執行所花的時間:

import time

def measuretime(func):

    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__, end - start)
        return result

    return wrapper

@measuretime
def count_down(n):
    while n > 0:
        n -= 1

if __name__ == '__main__':
    count_down(500000)

count_down 0.018976449966430664

使用 decorator @measure的來測量 count_down function所花費的時間。

2022年7月19日 星期二

[Python] 使用 Python的 venv建立虛擬環境

相關文章:
使用 Virtualenv 開發 Python

先前都是使用 Virtualenv來建立 Python開發的虛擬環境,但在 Python後面的版本,其本身就內 建了虛擬環境的模組 venv。

  • 使用 venv 建立虛擬環境
將路徑切換至需要建立虛擬環境的目錄下,並執行:
python -m venv [env_name]
env_name為所要建立虛擬環境的名稱,執行完後就會在目錄下產生名為 env_name的資料夾

  • 啟動虛擬環境
Windows:
[env_name]\Scripts\activate.bat
Unix like系統: source [env_name]/bin/activate
啟動成功後,視窗中會出現 [env_name]的提示字元,表示正在運行虛擬環境。
接下來,就可以使用 pip來安裝需要的模組,可參考:
套件管理程式 - pip

  • 離開虛擬環境
Windows:
[env_name]\Scripts\deactivate.bat

Reference:
https://docs.python.org/zh-tw/3/tutorial/venv.html

2021年5月13日 星期四

[Python] 將 Qt Designer的 .ui檔轉換成 .py檔

Qt Designer

PySide2

使用 pyside2-uic

pyside2-uic.exe <UI_FILE> -o <OUTPUT_FILE>

pyside2-uic預設安裝位置為%PYTHON_INSTALL_PATH%\Scripts\



PyQt5 & PyQt6

使用 pyuic5或 pyuic6

pyuic6.exe <UI_FILE> -o <OUTPUT_FILE>

pyuic5及 pyuic6預設安裝位置為%PYTHON_INSTALL_PATH%\Scripts\


2021年3月29日 星期一

[Python] Nuitka - 將Python 打包成執行檔


官方網址
https://nuitka.net
https://github.com/Nuitka

Windows


使用Nuitka 將hello.py 打包
python -m nuitka --mingw64 hello.py
打包時會要求下載 C Caching tool及 MinGW64 C compiler。


打包成一個獨立資料夾
python -m nuitka --mingw64 --standalone hello.py
執行完後會產生 .build及 .dist, .dist就是可以用來單獨執行的資料夾。

2018年9月13日 星期四

[Python] 套件管理程式 - pip


pip 是Python內建的套件管理的程式,用來安裝及管理Python的套件


pip install


安裝套件 pip install [MODULE_NAME]
安裝套件的特定版本 pip install [MODULE_NAME]==Version
更新套件至最新版本 pip install --upgrade [MODULE_NAME]
參考requirements.txt檔案安裝套件 pip install -r requirements.txt

pip show


顯示套件資訊 pip show [MODULE_NAME]

pip freeze


以requirements的形式顯示安裝的套件 pip freeze

pip uninstall


解除安裝套件 pip uninstall [MODULE_NAME]


保存套件的開發環境
可搭配virtualenv在乾淨的套件環境中使用

1. 使用pip freeze取出當前開發環境所使用的套件 python -m pip freeze > requirements.txt

2. 再用requirements.txt安裝開發環境的套件 python -m pip install -r requirements.txt

2018年8月27日 星期一

[Pythonic] 迴圈計數應用 enumerate()


在Python中,for迴圈可用來遍訪字串、串列等iterator,若要計算迴圈的數量,可在迴圈
中用counter來記錄。



seq = ["one", "two", "three", "four", "five"]
counter = 0
for e in seq:
  print (counter, e)
  counter += 1


1 one
2 two
3 three
4 four
5 five

另外還有比較Pythonic的寫法,就是使用enumerate (sequence, [start=0]) 函數。
sequence代入iterator,start則為起始位置。


seq = ["one", "two", "three", "four", "five"]
for idx, e in enumerate(seq):
  print (idx, e)


1 one
2 two
3 three
4 four
5 five


2018年5月14日 星期一

使用 Virtualenv 開發 Python



  • 安裝 Virtualenv

使用pip指令安裝Virtualenv

Windows:
> python -m pip install virtualenv


  • 使用 Virtualenv 建立虛擬環境

將路徑切換至Python需要建立虛擬環境的目錄下,並執行

Windows:
> python -m virtualenv [env_name]
env_name為所要建立虛擬環境的名稱,之後就會在目錄下產生名為[env_name]的資料夾


  • 運行虛擬環境

執行env_name/Scripts中的activate檔案

Windows:
> .\venv\Scripts\activate.bat

執行成功後,命令視窗就會出現目前正運行在虛擬環境中的提示字樣
(env_name)


  • 離開虛擬環境

執行env_name/Scripts中的deactivate檔案

Windows:
> .\venv\Scripts\deactivate.bat

若命令視窗中的提示字樣消失,就代表已經成功離開虛擬環境