vault backup: 2025-03-04 11:17:00

This commit is contained in:
2025-03-04 11:17:00 +08:00
parent d1e51bfd2f
commit ff12c4f4ca
161 changed files with 1 additions and 2 deletions

View File

@@ -0,0 +1,14 @@
```python
import os
import sys
config_name = 'myapp.cfg'
# determine if application is a script file or frozen exe
if getattr(sys, 'frozen', False):
application_path = os.path.dirname(sys.executable)
elif __file__:
application_path = os.path.dirname(__file__)
config_path = os.path.join(application_path, config_name)
```

View File

@@ -0,0 +1,34 @@
---
tags:
aliases:
date: 2024-11-10
time: 16:58:43
description:
---
**可以用來代替[Matplotlib](https://matplotlib.org/)**
Yes, `Matplotlib` is classic-its virtually the standard to go to when it comes to visualizing data in Python. But to be frank, it feels so much like trying to use an axe for delicate brain surgery, and its syntax? A little verbose, if were being honest. If youre not creating highly customized visualizations, there are better options with a more straightforward syntax.
## Why [Matplotlib](https://matplotlib.org/) is Overrated:
**Clunky syntax**: Even simple charts take an amazingly large number of lines to plot sometimes.
**Outdated default style:** The default style is configurable, but it isnt exactly inspiring-or, for that matter, particularly readable.
## What You Should Replace It With: Plotly
Where visualization cleanliness and interactivity matter, and definitely dont want a pile of code, `Plotly` is great. This is especially useful when you have to share visuals fast or within presentations on the web.
```python
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species")
fig.show()
```
With `Ploty`, you immediately get interactive graphs with great default visuals. The code is more concise and, by default, includes things like tooltips and zooming.
# 參考來源
- [5 Overrated Python Libraries (And What You Should Use Instead) | by Abdur Rahman | Nov, 2024 | Python in Plain English](https://python.plainenglish.io/5-overrated-python-libraries-and-what-you-should-use-instead-106bd9ded180)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
---
tags:
aliases:
date: 2024-11-10
time: 16:57:31
description:
---
**可以用來代替[pandas](https://pandas.pydata.org/)**
Now, listen up-the thing is, `Pandas` is great at data exploration and for middle-sized datasets. But people just use it for everything, like its some magic solution thats going to solve every problem in data, and quite frankly, it isnt. Working with `Pandas` on huge datasets can turn your machine into a sputtering fan engine, and memory overhead just doesnt make sense for some workflows.
## **Why [pandas](https://pandas.pydata.org/) Is Overrated:**
**Memory Usage:** As `Pandas` operates mainly in-memory, any operation on a large dataset will badly hit performance.
**Limited Scalability:** Scaling with `Pandas` isnt easy. It was never designed for big data.
## What You Should Use Instead: Polars
`Polars` is an ultra-fast DataFrame library in Rust using Apache Arrow. Optimized for memory efficiency and multithreaded performance, this makes it perfect for when you want to crunch data without heating up your CPU.
```python
import polars as pl
df = pl.read_csv("big_data.csv")
filtered_df = df.filter(pl.col("value") > 50)
print(filtered_df)
```
**Why** `**Polars**`**?** It will process data that would bring `Pandas` to its knees, and it handles operations in a fraction of the time. Besides that, it also has lazy evaluation-meaning it is only computing whats needed.
# 參考來源
- [5 Overrated Python Libraries (And What You Should Use Instead) | by Abdur Rahman | Nov, 2024 | Python in Plain English](https://python.plainenglish.io/5-overrated-python-libraries-and-what-you-should-use-instead-106bd9ded180)

View File

@@ -0,0 +1,45 @@
---
tags:
aliases:
date: 2024-11-10
time: 17:00:12
description:
---
**可以用來代替[scikit-learn](https://scikit-learn.org/stable/)**
I know, `Scikit-Learn` isnt supposed to be a deep learning library, but people use it as if it were. It is incredibly handy at quick prototyping and traditional machine learning models, but when it comes to neural networks, its just not in the same league as a library designed with tensors in mind.
## Why [scikit-learn](https://scikit-learn.org/stable/) is Overrated:
**No GPU Support:** Deep learning can be life-changing when training on GPUs. However, this is something that is not supported in `Scikit-Learn`.
**Not Optimized for Neural Networks:** `Scikit-learn` wasnt designed for doing deep learning; using it this way is reactively assured poor results.
## What You Should Use Instead: PyTorch
`PyTorch` is more general and supports GPU. Hence, its perfect for deep learning projects. Its Pythonic-this means for one coming from `Scikit-Learn`, it will feel natural, but with much more power.
import torch
import torch.nn as nn
import torch.optim as optim
# Define a simple model
```python
model = nn.Sequential(
nn.Linear(10, 5),
nn.ReLU(),
nn.Linear(5, 2)
)
```
# Define optimizer and loss
```python
optimizer = optim.SGD(model.parameters(), lr=0.01)
loss_fn = nn.CrossEntropyLoss()
```
If youre serious about deep learning, youll want to use a library worked out for the task at hand-which will save you from such limitations and inefficiencies. You will fine tune models with `PyTorch` and leverage the GPUs to your hearts content.
# 參考來源
- [5 Overrated Python Libraries (And What You Should Use Instead) | by Abdur Rahman | Nov, 2024 | Python in Plain English](https://python.plainenglish.io/5-overrated-python-libraries-and-what-you-should-use-instead-106bd9ded180)

View File

@@ -0,0 +1,173 @@
---
tags:
aliases:
date: 2025-03-02
time: 20:53:47
description:
---
# Project Structure
```
mlpredictor/
├── mlpredictor/
│ ├── __init__.py
│ ├── model.py
├── tests/
│ ├── test_model.py
├── LICENSE
├── README.md
├── pyproject.toml
└── .gitignore
```
## Content of `setup.py`
```
from setuptools import setup
setup(
name='mypackage',
version='0.1',
packages=['mypackage'],
install_requires=['requests'])
```
## Content of `pyproject.toml`
```toml
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "mlpredictor"
version = "0.1.0"
description = "A simple machine learning package using scikit-learn"
authors = [
{name = "Ebrahim", email = "ebimsv0501@gmail.com"}
]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.6"
dependencies = [
"scikit-learn>=1.0",
]
[project.urls]
"Homepage" = "https://github.com/ebimsv/mlpredictor"
```
- **[build-system]**: Specifies the build system requirements (i.e., using `setuptools` and `wheel`).
- **[project]**: Contains metadata about the package, like name, version, description, and dependencies.
## Content of `README.md`
<pre><code>
# MLPredictor
MLPredictor is a simple machine learning package that trains a RandomForest model using the Iris dataset and enables users to make predictions. The package is built using `scikit-learn` and is intended as a demonstration of packaging Python machine learning projects for distribution.
## Features
- Train a RandomForestClassifier on the Iris dataset.
- Make predictions on new data after training.
- Save and load trained models.
## Installation
You can install the package via **PyPI** or from **source**.
### Install from PyPI
```bash
pip install mlpredictor
```
### Install from Source (GitHub)
```bash
git clone https://github.com/ebimsv/mlpredictor.git
cd mlpredictor
pip install .
```
## Usage
After installation, you can use `MLPredictor` to train a model and make predictions.
### Example: Training and Making Predictions
```python
from mlpredictor import MLPredictor
# Initialize the predictor
predictor = MLPredictor()
# Train the model on the Iris dataset
predictor.train()
# Make a prediction on a sample input
sample_input = [5.1, 3.5, 1.4, 0.2]
prediction = predictor.predict(sample_input)
print(f"Predicted class: {prediction}")
```
</code></pre>
## Content of `.gitignore`
```
*.pyc
__pycache__/
*.pkl
dist/
build/
```
# Test
## Content of `tests/test_model.py`
```python
import pytest
from mlpredictor import MLPredictor
def test_train_and_predict():
model = MLPredictor()
model.train()
result = model.predict([5.1, 3.5, 1.4, 0.2])
assert len(result) == 1
if __name__ == "__main__":
pytest.main()
```
## Run test
```bash
pytest tests
```
# Install
## Test locally
```
pip install .
```
## Publish on PyPI
1. **Install 'Twine' and 'build'**:
```
pip install twine build
```
2. **Build the Package**:
```
python -m build
```
3. **Upload to PyPI**
```
twine upload dist/*
```
# 參考來源
- [Building Python Packages. A Comprehensive Guide to setup.py and… | by Ebrahim Mousavi | Medium](https://medium.com/@ebimsv/building-python-packages-07fbfbb959a9)

View File

@@ -0,0 +1,56 @@
一個範例:
```python
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--update_tool", default=WIN_FW_UPDATER_PATH, help="The path of win_fw_updater.exe.")
parser.add_argument("-f", "--firmware", required=True, help="The path of ITB file.")
parser.add_argument("-w", "--waittime_update_firmware", default=600, type=int, help="Wait time for update the firmware.")
parser.add_argument("-g", "--ignore_check_file_path", action='store_true', help="Skip check the existence of file.")
args = parser.parse_args()
```
#### 要求user一定要設定的參數
使用`required=True`
例如:
```python
parser.add_argument("-f", "--firmware", required=True, help="The path of ITB file.")
```
如果使用者沒有下`-f`(或者`--firmware=XXX`)就會報錯,如下:
```bash
FwUpdateCheck.py: error: the following arguments are required: -f/--firmware
```
#### 有設定才會產生的參數
使用`action='store_true'``action='store_false'`
例如:
```python
parser.add_argument("-g", "--ignore_check_file_path", action='store_true', help="Skip check the existence of file.")
```
當使用者沒有設置`-g`時,`args.ignore_check_file_path``False`,當設置時,`args.ignore_check_file_path``True`
#### 使用預設值
例如:
```python
parser.add_argument("-u", "--update_tool", default="C:\\tool.exe", help="The path of win_fw_updater.exe.")
```
`default=<Something>`來設定參數的預設值,上面的例子中,`args.update_tool`的預設值為`C:\tool.exe`
另外可以用`type=<Object type>`來指定預設值的型別。例如:
```python
parser.add_argument("-n", "--number", default=50, type=int, help="Assign a number")
```
上例中,`args.number`的預設值是50型別是`int`,所以可以直接運算,不需要再經過`int(args.number)`這樣的轉換。
#### 限制使用者的選擇
Example:
```python
parser.add_argument('move', choices=['rock', 'paper', 'scissors'])
```
使用`choices=<list>`來限定輸入的選項,上例中,使用者只能輸入'rock'、'paper'、'scissors'這三個字串中的其中一個,否則會報錯:
```bash
error: argument move: invalid choice: 'fire' (choose from 'rock', 'paper', 'scissors')
```
-----
- https://docs.python.org/zh-tw/3/library/argparse.html

View File

@@ -0,0 +1,5 @@
從list中選出n個項目有可能重複
```python
import random
random.choices(seq, n)
```

View File

@@ -0,0 +1,48 @@
## 在decorator內取得function的default argument與class member
```python
import sys
import inspect
from functools import wraps
def exampleDecorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Decorator: call by {func.__name__}")
def get_default_args(func):
signature = inspect.signature(func)
return {
k: v.default for k, v in signature.parameters.items() if v.default is not inspect.Parameter.empty
}
## Get default
defaultKwargs = get_default_args(func)
defaultKwargs.update(kwargs)
print(f"Decorator: args = {args}, kwargs = {kwargs}, defaultKwargs = {defaultKwargs}")
objectInstance = args[0]
if hasattr(objectInstance, 'defaultArg1'):
print(f'objectInstance has defaultArg1, a.defaultArg1({type(objectInstance.defaultArg1)}) = {objectInstance.defaultArg1}')
if objectInstance.defaultArg1:
## Do something here
print("Decorator: some message...")
else:
print('objectInstance does not have defaultArg1')
return func(*args, **kwargs)
return wrapper
class ExampleClass():
def __init__(self, defaultArg1=True, defaultArg2="SomeString"):
self.defaultArg1 = defaultArg1
self.defaultArg2 = defaultArg2
print(f'self.defaultArg1 = {self.defaultArg1}, self.defaultArg2 = {self.defaultArg2}')
@exampleDecorator
def run(self, arg1=1, arg2=2):
print(f"ExampleClass.run(), arg1 = {arg1}, arg2 = {arg2}")
example = ExampleClass()
example.run()
```

View File

@@ -0,0 +1,36 @@
---
tags:
aliases:
date: 2024-11-10
time: 16:54:12
description:
---
**可以用來代替[requests](https://pypi.org/project/requests/)**
## **Why [requests](https://pypi.org/project/requests/) is Overrated:**
**Blocking IO:** `Requests` is synchronous, which means each call waits for the previous call to finish. This is less than ideal when working with I/O-bound programs.
**Heavy:** Its got loads of convenience baked in, but it does have a cost in terms of speed and memory footprint. Not a big deal on a simple script, but on larger systems this can be a resource hog.
## **What You Should Instead Use:** `httpx`
For parallel processing of requests, `httpx`provides a similar API but with asynchronous support. So, if you make many API calls, itll save you some time and resources because it will process those requests concurrently.
```python
import httpx
async def fetch_data(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.json()
# Simple and non-blocking
data = fetch_data("https://api.example.com/data")
```
> **Pro Tip:** Asynchronous requests can reduce the processing time by a great amount if the task at hand is web scraping or ingesting data from somewhere.
# 參考來源
- [5 Overrated Python Libraries (And What You Should Use Instead) | by Abdur Rahman | Nov, 2024 | Python in Plain English](https://python.plainenglish.io/5-overrated-python-libraries-and-what-you-should-use-instead-106bd9ded180)

View File

@@ -0,0 +1,4 @@
- [Python 中的 Log 利器:使用 logging 模組來整理 print 訊息 - zhung to be lazy…](https://zhung.com.tw/article/python%E4%B8%AD%E7%9A%84log%E5%88%A9%E5%99%A8-%E4%BD%BF%E7%94%A8logging%E6%A8%A1%E7%B5%84%E4%BE%86%E6%95%B4%E7%90%86print%E8%A8%8A%E6%81%AF/)\
- [[Python] logging 教學](https://zwindr.blogspot.com/2016/08/python-logging.html)
- [How can I color Python logging output? - Stack Overflow](https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output)
- [logging如何使用 logging 紀錄事件 - Andrew Li](https://orcahmlee.github.io/python/python-logging/)

View File

@@ -0,0 +1,126 @@
### 準備
```
import logging
```
### logging level
| level | level number | funtion |
|:---------|:-------------|:---------------------|
| NOTSET | 0 | |
| DEBUG | 10 | `logging.debug()` |
| INFO | 20 | `logging.info()` |
| WARNING | 30 | `logging.warning()` |
| ERROR | 40 | `logging.error()` |
| CRITICAL | 50 | `logging.critical()` |
```
import logging
LOG_FORMAT = '%(asctime)s %(levelname)s: %(message)s'
LOG_FILENAME = 'C:\\RobotRun\\Output\\RobotRunDocUpdater.log'
logging.basicConfig(level=logging.INFO, filename=LOG_FILENAME, filemode='a', format=LOG_FORMAT)
logging.info('logging start')
```
### Print Exception
`logging` 模組也提供可以紀錄完整的堆疊追蹤 (stack traces),若在 `logging.error()` 加上 `exc_info` 參數,並將該參數設為 `True`,就可以紀錄 Exception如下
```python
import logging
try:
x = 5 / 0
except:
logging.error("Catch an exception.", exc_info=True)
```
也可以使用`logging.exception("Catch an exception.")`,效果跟`logging.error("Catch an exception.", exc_info=True)`一樣。
### 自訂 logging 輸出格式
預設的訊息輸出格式只有 `levelname``name``message`,下面是其他相關的資訊:
| 格式化字串 | 說明 |
|:------------------|:---------------------------------------------------------------------|
| `%(asctime)s` | 日期時間, 格式為 `YYYY-MM-DD HH:mm:SS,ms`例如2018-12-13 17:20:30,567 |
| `%(filename)s` | 模組檔名 |
| `%(funcName)s` | 函數名稱 |
| `%(levelname)s` | 日誌的等級名稱 |
| `%(levelno)s` | 日誌的等級數值 |
| `%(lineno)d` | 呼叫日誌函數所在的行數 |
| `%(message)s` | 訊息 |
| `%(module)s` | 模組名稱 |
| `%(name)s` | logger 的名稱 |
| `%(pathname)s` | 檔案的完整路徑 (如果可用) |
| `%(process)d` | process ID (如果可用) |
| `%(thread)d` | 執行緒 ID (如果可用) |
| `%(threradName)s` | 執行緒名稱 |
例:
```python
FORMAT = '%(asctime)s %(levelname)s: %(message)s'
logging.basicConfig(level=logging.DEBUG, format=FORMAT)
logging.debug('debug message') --> 2018-12-13 17:40:34,604 DEBUG: debug message
```
### 儲存log
只要在 `logging.basicConfig()` 內的 `filename` 參數設定要儲存的日誌檔名,就可以將 logging 儲存:
```python
import logging
FORMAT = '%(asctime)s %(levelname)s: %(message)s'
logging.basicConfig(level=logging.DEBUG, filename='myLog.log', filemode='w', format=FORMAT)
logging.debug('debug message')
```
預設 `filemode` 參數是設為 `a`,代表 append (附加) 的意思每次執行程式時Logging 會將新的訊息加在舊的訊息後面,不會覆蓋舊的訊息。若要改成新訊息覆蓋就訊息,那可以將 `filemode` 參數設為 `w`,代表 write 的意思。
### 儲存log也輸出到console
`logging`有4個主要module
- Logger暴露了應用程式程式碼能直接使用的介面。
- Handler記錄器產生的日誌記錄傳送至合適的目的地。
- Filter提供了更好的粒度控制它可以決定輸出哪些日誌記錄。
- Formatter指明瞭最終輸出中日誌記錄的佈局。
#### Handler
其中`Handlers`有以下幾類:
1. `logging.StreamHandler` -> 控制檯輸出
使用這個Handler可以向類似與`sys.stdout`或者`sys.stderr`的任何檔案物件(file object)輸出資訊。
它的建構函式是: `StreamHandler([strm])` 其中`strm`引數是一個檔案物件。預設是`sys.stderr`
2. `logging.FileHandler` -> 檔案輸出
和StreamHandler類似用於向一個檔案輸出日誌資訊。不過`FileHandler`會幫你開啟這個檔案。
它的建構函式是:`FileHandler(filename[,mode])` filename是檔名必須指定一個檔名。 `mode`是檔案的開啟方式。預設是`'a'`,即新增到檔案末端。
3. `logging.handlers.RotatingFileHandler` -> 按照大小自動分割日誌檔案,一旦達到指定的大小重新生成檔案
這個Handler類似於上面的`FileHandler`但是它可以管理檔案大小。當檔案達到一定大小之後它會自動將當前日誌檔案改名然後建立一個新的同名日誌檔案繼續輸出。比如日誌檔案是chat.log。當chat.log達到指定的大小之後`RotatingFileHandler`自動把 檔案改名為chat.log.1。不過如果chat.log.1已經存在會先把chat.log.1重新命名為chat.log.2。
最後重新建立 chat.log繼續輸出日誌資訊。它的建構函式是`RotatingFileHandler(filename[, mode[, maxBytes[, backupCount]]])`,其中`filename``mode`兩個引數和FileHandler一樣。`maxBytes`用於指定日誌檔案的最大檔案大小。如果maxBytes為0意味著日誌檔案可以無限大這時上面描述的重新命名過程就不會發生。 `backupCount`用於指定保留的備份檔案的個數。比如如果指定為2當上面描述的重新命名過程發生時原有的chat.log.2並不會被更名,而是被刪除。
4. `logging.handlers.TimedRotatingFileHandler` -> 按照時間自動分割日誌檔案
這個Handler和`RotatingFileHandler`類似,不過,它沒有通過判斷檔案大小來決定何時重新建立日誌檔案,而是間隔一定時間就自動建立新的日誌檔案。重新命名的過程與`RotatingFileHandler`類似,不過新的檔案不是附加數字,而是當前時間。它的建構函式是:`TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])`,其中`filename`引數和`backupCount`引數和`RotatingFileHandler`具有相同的意義。`interval`是時間間隔。 `when`引數是一個字串。表示時間間隔的單位,不區分大小寫。它有以下取值: S 秒 M 分 H 小時 D 天 W 每星期(`interval==0`時代表星期一) midnight 每天凌晨。
#### Formatters
Formatters預設的時間格式為`%Y-%m-%d %H:%M:%S`
#### Example
新增2個handler一個輸出到螢幕上一個寫到檔案裡。寫到檔案裡的那個handler必須是`logging.handlers.RotatingFileHandler`超過1MB時會自動分割。
```python
import logging
import logging.handlers
logger = logging.getLogger(filename) # filename就是你要存log的檔名
shell_print = logging.StreamHandler() # 往螢幕上輸出
shell_print.setFormatter(format_str) # 設定螢幕上顯示的格式
file_print = logging.handlers.RotatingFileHandler(
filename=filename,
mode='a',
maxBytes=1024*1024,
backupCount=backCount,
encoding='utf-8')
file_print.setFormatter(format_str) # 設定檔案裡寫入的格式
logger.addHandler(sh) # 把物件加到logger裡
logger.addHandler(th)
```
-----
參考:
- [Python - 日誌 (logging) 模組](https://titangene.github.io/article/python-logging.html)
- [`logging` — Logging facility for Python](https://docs.python.org/3/library/logging.html#module-logging "logging: Flexible event logging system for applications.")

View File

@@ -0,0 +1,72 @@
## 基本折線圖
給2個list一個 x一個 y
```python
plt.clf() # 把圖清掉,變空白
plt.plot(xList, yList)
```
## XY軸標籤
```python
plt.xlabel(
'Focus setting', # 標籤
fontsize=15, # 字型大小
labelpad=10, # 標籤留白
color='red', # 文字顏色
rotation=90, # 文字旋轉角度
fontweight='bold', # 粗體
)
```
## 不要顯示軸的刻線
```python
plt.gca().axes.get_xaxis().set_visible(False)
```
## 畫2張圖
```python
figure, axis = plt.subplots(2, 2)
```
`plt.subplots()` 來指定要畫幾張圖,第一個參數是要有幾個 row第二個參數是要有幾個 column。
`axis` 會是一個 array可以用類似座標的方式來控制你要的圖例如
```python
axis[0, 0].set_title("Sine Function")
axis[0, 1].set_title("Cosine Function")
```
`figure` 則是指外圍的大圖。
## 畫2條線
```python
plt.plot(x, y1, label='sine curve',color='b')
plt.plot(x, y2, label='cosine curve',color='r')
```
## 畫大圖
```python
figure(figsize=(12, 9), dpi=120)
```
`12``9`指的是英吋,`dpi`是每英吋幾個點,所以就是`12*120``9*120`,也就是`1440x1080`
## 存檔
```python
plt.savefig(f'plot_{folder}.png')
```
## 註記annotation
```python
ax = plt.gca()
ax.annotate(
'local max', # 註記文字
xy=(xmax, ymax), # 點的座標
xytext=(xmax, ymax + 5), # 文字的座標
arrowprops=dict( # 箭頭的屬性
facecolor='black', # 顏色:黑色
shrink=0.05), #
)
```
官方說明:[matplotlib.axes.Axes.annotate — Matplotlib 3.7.1](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.annotate.html)
## 在X軸上畫一個範圍
```python
plt.gca().axvspan(startXPos, endXPos, alpha=0.2, color='red')
```

View File

@@ -0,0 +1,61 @@
### 將camera包裝成class
```python
class CameraCv(object):
def __init__(self, videoSource=0):
self.videoSource = videoSource
self.camera = None
self.cameraWidth = 0
self.cameraHeight = 0
self.cameraPreviewThreadHandle = None
self.cameraPreviewThreadStopEvent = threading.Event()
self.lastframeRGB = None
self.latestFrame = None
def start(self):
print("Open Camera")
self.camera = cv2.VideoCapture(self.videoSource, cv2.CAP_DSHOW)
if not self.camera.isOpened():
raise ValueError("Unable to open video source {}".format(self.videoSource))
# Get video source width and height
self.cameraWidth = self.camera.get(cv2.CAP_PROP_FRAME_WIDTH)
self.cameraHeight = self.camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
self.cameraPreviewThreadStopEvent.clear()
self.cameraPreviewThreadHandle = threading.Thread(target=self.collectFrame, daemon=True, args=())
self.cameraPreviewThreadHandle.start()
def stop(self):
print("Close Camera")
self.cameraPreviewThreadStopEvent.set()
if self.camera.isOpened():
self.camera.release()
cv2.destroyAllWindows()
def collectFrame(self):
while True:
ret, frame = self.camera.read()
if ret:
# Return a boolean success flag and the current frame converted to BGR
self.lastframeRGB = frame
self.latestFrame = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)))
if self.cameraPreviewThreadStopEvent.is_set():
break
time.sleep(0.016)
def draw(self, container):
if self.latestFrame is not None:
container.imgtk = self.latestFrame
container.configure(image=self.latestFrame)
def read(self):
return self.camera.read()
def getLastFrameRgb(self):
return self.lastframeRGB
def saveFrame(self, filepath):
cv2.imwrite(filepath, self.getLastFrameRgb())
```

View File

@@ -0,0 +1,7 @@
從一個list中選出n個不重複的項目
```python
import random
random.sample(seq, n)
```
不像 [[choices()]] 是會重複的。

View File

@@ -0,0 +1,35 @@
---
tags:
aliases:
date: 2024-11-10
time: 16:55:41
description:
---
**可以用來代替[Beautiful Soup Documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/)**
## **Why [Beautiful Soup Documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) is Overrated:**
**Speed:** Not very fast, when the size of a document is very big.
**Thread blocking:** Much like `Requests` itself, it is not designed with async in mind, which certainly makes it ill-suited for scraping dynamic websites.
## **Instead What you should use:** `selectolax`
`selectolax` is a less famous library that uses `libxml2` for better performance and with less memory consumption.
```python
from selectolax.parser import HTMLParser
html_content = "<html><body><p>Test</p></body></html>"
tree = HTMLParser(html_content)
text = tree.css("p")[0].text()
print(text) # Output: Test
```
As it will turn out, by using `Selectolax`, you retain the same HTML parsing capabilities but with much-enhanced speed, making it ideal for web scraping tasks that are quite data-intensive.
> **“Do not fall in love with the tool; rather, fall in love with the outcome.” Choosing the proper tool is half the battle.**
# 參考來源
- [5 Overrated Python Libraries (And What You Should Use Instead) | by Abdur Rahman | Nov, 2024 | Python in Plain English](https://python.plainenglish.io/5-overrated-python-libraries-and-what-you-should-use-instead-106bd9ded180)

View File

@@ -0,0 +1,49 @@
### subprocess.Popen
```python
import subprocess
process = subprocess.Popen(['echo', 'More output'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
stdout, stderr
```
Input arguments is a list.
Notice `communicate()` will **block** until process was finished.
And the output string `stdout` and `stderr` is of type `byte`. You can convert the output to `string` by:
```python
new_string = stdout.decode('utf-8')
```
or use `universal_newlines=True` in `subprocess.Popen()`. Example:
```python
process = subprocess.Popen(['ping', '-c 4', 'python.org'],
stdout=subprocess.PIPE,
universal_newlines=True)
```
The `.poll()` will return the exit code of process. If process is still running. `.poll()` will return `None`. Example:
```python
process = subprocess.Popen(['ping', '-c 4', 'python.org'], stdout=subprocess.PIPE, universal_newlines=True)
while True:
output = process.stdout.readline()
print(output.strip())
# Do something else
return_code = process.poll()
if return_code is not None:
print('RETURN CODE', return_code)
# Process has finished, read rest of the output
for output in process.stdout.readlines():
print(output.strip())
break
```
-----
參考:
- [docs.python.org: `subprocess.Popen`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen)
### subprocess.run
`subprocess.run()``subprocess.Popen()`是一樣的行為,差別是`subprocess.run()`會在process執行完畢之後才return也就是說流程會被block住。
`subprocess.run()`會回傳一個型別是`subprocess.CompletedProcess`的object.
-----
參考:
- [docs.python.org: _class_ `subprocess.CompletedProcess`](https://docs.python.org/3/library/subprocess.html#subprocess.CompletedProcess)

View File

@@ -0,0 +1,2 @@
- [Python 多執行緒 threading 模組平行化程式設計教學 - G. T. Wang](https://blog.gtwang.org/programming/python-threading-multithreaded-programming-tutorial/)
- [Python — 多線程. 介紹 | by Jease | Jease隨筆 | Medium](https://medium.com/jeasee%E9%9A%A8%E7%AD%86/python-%E5%A4%9A%E7%B7%9A%E7%A8%8B-eb36272e604b)

View File

@@ -0,0 +1,96 @@
### 把[[matplotlib]]包裝成獨立視窗
```python
class Plot2D(Frame):
def __init__(self, parent, dataCollector, **kwargs):
Frame.__init__(self, parent.mainWindow, **kwargs)
self.parent = parent
self.mainWindows = Toplevel(parent.mainWindow)
self.mainWindows.title("AF State")
self.figure = plt.Figure(figsize=(9,5), dpi=100)
self.figure.suptitle('AF value plot', fontsize=16)
self.ax = self.figure.add_subplot(111)
self.canvas = FigureCanvasTkAgg(self.figure, master=self.mainWindows)
self.canvas.get_tk_widget().pack(fill='both')
self.axline = None
self.dataCollector = dataCollector
self.dataCollector.start()
def close(self):
print("Plot2D close")
self.mainWindows.destroy()
self.dataCollector.stop()
self.dataCollector = None
def draw(self):
if self.dataCollector:
datax, datay = self.dataCollector.getPlotData()
self.ax.clear()
self.ax.set_xlabel('Last {} datas'.format(self.dataCollector.getDataLength()))
self.axline, = self.ax.plot(datax, datay)
self.canvas.draw()
def getWindow(self):
return self.mainWindows
def getLastData(self):
return self.dataCollector.getLastData()
```
其中這一行:
```python
self.mainWindows = Toplevel(parent.mainWindow)
```
是用來開一個新的視窗,其中的`parent.mainWindow`就是用`tk.TK()`所產生出來的root。
因為需要一直更新資料,所以需要的一個`DataCollector`來提供資料,`DataCollector`會提供畫圖需要的list
```python
datax, datay = self.dataCollector.getPlotData()
```
`DataCollector`的定義如下:
```python
class AfStateCollector(threading.Thread):
def __init__(self, dataLength=100, pollingInterval=0.033):
threading.Thread.__init__(self)
self.dataLength = dataLength
self.pollingInterval = pollingInterval
self.stopEvent = threading.Event()
self.data = []
self.xdata = []
def run(self):
while True:
if self.stopEvent.is_set():
break
afValue = self.readAf()
self.data.append(afValue)
self.xdata.append(len(self.xdata))
if len(self.data) > self.dataLength:
self.data = self.data[-self.dataLength:]
self.xdata = list(range(self.dataLength))
# print(f'afValue = {afValue}')
time.sleep(self.pollingInterval)
print("AfStateCollector stopped.")
def readAf(self):
ReadTestXUreg_cmd = "lvreg testxu read 10"
ReadTestXUreg_cmd_process = subprocess.Popen(ReadTestXUreg_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
outstring, err = ReadTestXUreg_cmd_process.communicate()
outstring = outstring.strip().decode('utf-8')
outstring = int(outstring, 16)
outstring_H = (outstring & 0xFF00) / 256
outstring_L = outstring & 0xFF
outAFStat = int(outstring_L * 256 + outstring_H)
return outAFStat
```
- [Python GUI之tkinter視窗視窗教程大集合看這篇就夠了 - IT閱讀](https://www.itread01.com/content/1547705544.html)
- [【Python】改善 VideoCapture 的影像延遲 | 夏恩的程式筆記 - 點部落](https://dotblogs.com.tw/shaynling/2017/12/28/091936)
- [Displaying a video feed with OpenCV and Tkinter - PyImageSearch](https://www.pyimagesearch.com/2016/05/30/displaying-a-video-feed-with-opencv-and-tkinter/)

View File

@@ -0,0 +1,96 @@
## 單元測試
### [pytest](https://docs.pytest.org/en/7.1.x/)
Pytest 不僅可以幫助我們運行測試還可以幫助我們配置如何運行它們、運行哪些文件等等……Pytest 有一個配置文件 `pytest.ini`,您可以在其中描述它的配置,例如哪個版本應該是 Pytest 或者哪些是測試文件,例如下列。
```ini
# pytet.ini
[pytest]
minversion = 6.0
addopts = -ra -q — cov=src — cov-report=html
python_files = test_*.py
```
### [tox](https://tox.wiki/en/latest/)
Tox 是一個通用的virtualenv管理和測試命令行工具。
使用不同的 Python 版本和解釋器檢查您的包是否正確安裝
在每個環境中運行您的測試,配置您選擇的測試工具
作為持續集成服務器的前端,大大減少樣板文件並合併 CI 和基於 shell 的測試。
Tox 也有它的配置文件。
```ini
[tox]
isolated_build = True
envlist = py{38}
[testenv]
usedevelop = true
deps = -r src/requirements_dev.txt
```
## 程式檢查工具
用來檢查程式是否符合coding style、PEP8之類的規範
### [pylint](https://github.com/PyCQA/pylint)
Pylint config: create `.pylintrc` file
```
[MESSAGES CONTROL]
disable=
missing-docstring,
too-few-public-methods[REPORTS]
output-format=colorized
files-output=no
reports=no
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
```
### [flake8](https://github.com/pycqa/flake8)
Flake8 config: create `.flake8` file
```
[flake8]
ignore = E203, E266, E501, W503, F403, F401, E402
max-line-length = 120
max-complexity = 18
select = B,C,E,F,W,T4,B9
exclude =
.git,
tests
```
### [mypy](http://www.mypy-lang.org/)
## Git hook
### pre-commit
Pre-commit 是一個創建 git hook的framework以確保您的代碼編寫與您定義的代碼樣式相對應。
它會掃描您的原始碼並運行您將在預提交配置文件中定義的所有檢查器:`.pre-commit-config.yaml`
```
repos:
- repo: 'https://gitlab.com/pycqa/flake8'
rev: 3.8.2
hooks:
- id: flake8
name: Style Guide Enforcement (flake8)
args:
- '--max-line-length=120'
- repo: 'https://github.com/pre-commit/mirrors-mypy'
rev: v0.720
hooks:
- id: mypy
name: Optional Static Typing for Python (mypy)
```
## 漏洞檢查
### [SonarQube](https://www.sonarqube.org/)
有很多用於漏洞掃描的工具,但我們將看看[Sonarqube](https://www.sonarqube.org/)。Sonarqube 是用於代碼質量和安全掃描的開源強大工具,是該行業的領先工具之一。
更多在[官方文檔](https://docs.sonarqube.org/latest/)中。
您可以使用 Docker 映像設置本地 Sonarqube 服務器並定義`sonar-project.properties`
```
# must be unique in a given SonarQube instance
sonar.projectKey=python_app_blueprint
# --- optional properties ---
# defaults to project key
#sonar.projectName=My project
# defaults to 'not provided'
#sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Defaults to .
#sonar.sources=.
# Encoding of the source code. Default is default system encoding
#sonar.sourceEncoding=UTF-8
```