用量子計算模擬器ProjectQ生成隨機數,並用pytest進行單元測試與覆蓋率測試
阿新 • • 發佈:2021-03-01
# 技術背景
本文中主要包含有三個領域的知識點:隨機數的應用、量子計算模擬產生隨機數與基於pytest框架的單元測試與覆蓋率測試,這裡先簡單分別介紹一下背景知識。
## 隨機數的應用
在上一篇介紹[量子態模擬取樣](https://www.cnblogs.com/dechinphy/p/state.html)的演算法中,我們就使用到了隨機數,隨機數在各種蒙特卡洛方法與數值計算中,扮演著非常重要的角色。在金融領域,隨機數則是在加密演算法中扮演重要角色,其風險在於,如果隨機數可被預測,那麼惡意使用者就可以利用這一特點,破解對稱加密甚至是非對稱加密的演算法(非對稱加密如RSA演算法的私鑰的挑選其實也有可能使用到隨機數)。在python程式碼中,可以通過呼叫random庫或者numpy.random庫進行隨機數的生成,僅需要通過如下的程式碼即可實現:
```python
import random
random_number = random.random() # 產生[0,1)之間的均勻隨機數
import numpy as np
random_array = random.randn(10) # 產生10個隨機數並存儲到np格式的一維陣列中
```
這些庫所產生的隨機數,往往被認為是不安全的隨機數,其主要特點是通過隨機數生成演算法,結合硬體的一些獨有編號來產生一系列數串。但是隨機數生成演算法一般都是已知的,因此還是有一定的潛在風險。有一個python庫函式叫`secrets`可以產生"安全隨機數",其特點在於不僅利用了一些硬體系統獨有資訊,如ip和MAC等,主要還利用了系統熵源來生成隨機數,增強了所產生隨機數的不可預測性。關於`secrets`的使用方法, 可以參考其[官方文件](https://docs.python.org/3/library/secrets.html#random-numbers)。但是,即使是這裡所謂的`安全隨機數`,也並不是`真隨機數`,真隨機數的產生不依賴於演算法。
## 量子計算與隨機數
前面寫過一篇部落格介紹[兩位元量子系統的模擬](https://www.cnblogs.com/dechinphy/p/magic.html),讀者可以從中瞭解到量子計算的一些基本原理與模擬實現。而另一篇關於[量子線路模擬](https://www.cnblogs.com/dechinphy/p/circuit.html)的部落格,則介紹了關於開源量子計算框架ProjectQ的一些基本使用方法,在這篇文章中我們也會使用到。通過量子硬體,我們可以直接讀取一系列的隨機串,由於這些隨機串是由硬體直接給出來的結果,不是通過演算法來生成的,因此是完成不可預測的,被稱為"真隨機數"。
## 基於pytest的python單元測試框架
在使用python程式設計實現演算法時,需要對演算法函式或者類進行功能驗證,這就需要寫測試用例。python第三方庫pytest提供了非常好的自動化測試的功能,配合html外掛和覆蓋率測試外掛,還可以進行更多的測試以及更好的展示測試的結果。
# 量子計算產生隨機數
量子計算是基於量子疊加與量子糾纏兩種特性進行計算的方案,其結合量子演算法的複雜性優勢,在量子處理器上可以實現經典計算機無法在有效時間內完成的任務,一般稱之為量子優越性。量子疊加是對量子位元重要特性的一個總結,如下圖所示(圖片來自於參考連結1),區分於經典位元,量子位元不僅可以表示`0`和`1`,還可以表示處於`0`和`1`之間的狀態,比如`0.5`,`0.2243`等等。這些狀態我們不能直接讀取,在硬體上我們只能夠讀取到`0`或者`1`兩種狀態,這跟經典位元是一樣的。區別在於,即使我們不改變數子位元的狀態,不同的測試卻會給出不同的結果,而`0.5`等中間狀態,則表示的是出現`0`或者`1`狀態分別的概率。
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228221328677-1165684319.png)
由於量子測量會導致量子態的坍縮,也就是說,每一次測量之後,都需要重新制備量子態。而製備一個產生隨機數的量子態,我們可以用如下所示的$H$量子門操作來實現。其具體的矩陣表述可以參考[這篇部落格](https://www.cnblogs.com/dechinphy/p/circuit.html),量子計算本質上就是用特殊的硬體方法,快速的實現大規模的矩陣運算,這也是其展現量子優勢的來源。
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228214704151-1207120775.png)
這裡我們直接使用開源量子計算框架ProjectQ來實現這個門操作,就省去了自己去模擬實習的繁瑣操作:
```python
# random_number.py
from projectq import MainEngine
from projectq.ops import H, Measure
def random_number_generator():
eng = MainEngine()
qubit = eng.allocate_qubit()
H | qubit
eng.flush()
Measure | qubit
random_number = int(qubit)
eng.flush(deallocate_qubits=True)
return random_number
if __name__ == '__main__':
random_number = random_number_generator()
print ('Random number generated by quantum simulator is: {}'.format(random_number))
```
這裡順帶的介紹下ProjectQ的一些操作實現的方法,在ProjectQ中將眾多的量子位元作為暫存器來進行呼叫,這些暫存器都在給定的engine下賦予了各種操作,如量子門操作、列印線路、編譯優化等。程式設計框架與實際的量子位元並不在架構上的同一個層次,每次傳送指令都是通過eng.flush()打包進行編譯優化之後,再傳送到後端去逐一執行。因此如果要測量量子位元(在ProjectQ模擬器中必須只能全部執行測量操作,不能只測量其中的某一個部分),或者是讀取某一個量子態的概率時,都需要先執行eng.flush()才行。接下來簡單看下上述程式碼的執行效果:
```bash
[dechin@dechin-manjaro pytest]$ python3 random_number.py
Random number generated by quantum simulator is: 1
[dechin@dechin-manjaro pytest]$ python3 random_number.py
Random number generated by quantum simulator is: 1
[dechin@dechin-manjaro pytest]$ python3 random_number.py
Random number generated by quantum simulator is: 0
[dechin@dechin-manjaro pytest]$ python3 random_number.py
Random number generated by quantum simulator is: 0
[dechin@dechin-manjaro pytest]$ python3 random_number.py
Random number generated by quantum simulator is: 1
```
在這個案例中,每一次都會產生一個新的隨機數0或者1,並且在量子位元使用結束之後,通過eng.flush(deallocate_qubits=True)可以初始化該暫存器,所有的振幅和測量結果都會被丟棄。
## 注意!!!
需要注意的是,由於這裡我們是使用了模擬器來模擬量子計算機的行為,因此得到的隨機數結果還是偽隨機數。只有當這一串程式碼執行在量子處理器上時,我們才能得到真隨機數。
# pytest測試
## 安裝pytest庫
首先我們可以通過pip來更新安裝pytest:
```bash
[dechin@dechin-manjaro pytest]$ python3 -m pip install -U pytest
Collecting pytest
Downloading pytest-6.2.2-py3-none-any.whl (280 kB)
|████████████████████████████████| 280 kB 464 kB/s
Requirement already satisfied, skipping upgrade: iniconfig in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (1.1.1)
Requirement already satisfied, skipping upgrade: pluggy<1.0.0a1,>=0.12 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (0.13.1)
Requirement already satisfied, skipping upgrade: attrs>=19.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (20.3.0)
Requirement already satisfied, skipping upgrade: toml in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (0.10.1)
Requirement already satisfied, skipping upgrade: packaging in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (20.4)
Requirement already satisfied, skipping upgrade: py>=1.8.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest) (1.9.0)
Requirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest) (2.4.7)
Requirement already satisfied, skipping upgrade: six in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest) (1.15.0)
Installing collected packages: pytest
Attempting uninstall: pytest
Found existing installation: pytest 6.2.1
Uninstalling pytest-6.2.1:
Successfully uninstalled pytest-6.2.1
Successfully installed pytest-6.2.2
```
安裝完成後,可以通過如下指令來檢視安裝的pytest版本:
```bash
[dechin@dechin-manjaro pytest]$ pytest --version
pytest 6.2.2
```
## pytest單元測試用例撰寫
根據前面一個章節中的`random_number.py`檔案,我們可以對照的寫一個簡單測試用例:
```
# test_random_number.py
import pytest
from random_number import random_number_generator as rng
def test_random_number_generator():
for i in range(10):
random_number = rng()
assert random_number == 0 or random_number == 1
```
該測試用例的含義為:匯入rng函式之後,測試10次該函式的返回值,所返回的值必須是0或者1的隨機數,如果輸出了這兩個數字以外的返回結果,那麼說明這個隨機數產生器功能上存在問題。基於pytest的測試程式碼可以通過如下的指令來執行:
```bash
[dechin@dechin-20n2s01200 pytest]$ py.test
=========================================== test session starts ============================================
platform linux -- Python 3.8.5, pytest-6.2.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/dechin/projects/2021-python/pytest
plugins: cov-2.11.1, metadata-1.11.0, html-3.1.1
collected 1 item
test_random_number.py . [100%]
============================================= warnings summary =============================================
../../../anaconda3/lib/python3.8/site-packages/projectq/ops/_gates.py:118
/home/dechin/anaconda3/lib/python3.8/site-packages/projectq/ops/_gates.py:118: PendingDeprecationWarning: the matrix subclass is not the recommended way to represent matrices or deal with linear algebra (see https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html). Please adjust your code to use regular ndarray.
return np.matrix([[1, 0], [0, 1j]])
../../../anaconda3/lib/python3.8/site-packages/projectq/ops/_gates.py:133
/home/dechin/anaconda3/lib/python3.8/site-packages/projectq/ops/_gates.py:133: PendingDeprecationWarning: the matrix subclass is not the recommended way to represent matrices or deal with linear algebra (see https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html). Please adjust your code to use regular ndarray.
return np.matrix([[1, 0], [0, cmath.exp(1j * cmath.pi / 4)]])
test_random_number.py: 40 warnings
/home/dechin/anaconda3/lib/python3.8/site-packages/projectq/ops/_gates.py:69: PendingDeprecationWarning: the matrix subclass is not the recommended way to represent matrices or deal with linear algebra (see https://docs.scipy.org/doc/numpy/user/numpy-for-matlab-users.html). Please adjust your code to use regular ndarray.
return 1. / cmath.sqrt(2.) * np.matrix([[1, 1], [1, -1]])
-- Docs: https://docs.pytest.org/en/stable/warnings.html
====================================== 1 passed, 42 warnings in 0.50s ======================================
```
從返回的結果來看,出現了`1 passed`而沒有failed,說明所有的測試用例都已經執行成功了,但是這裡存在不少的告警`warnings`資訊。
## pytest初始化配置檔案
在上一節的測試結果中,我們發現有非常多的測試告警。假如我們確認這些告警資訊可以忽略,那麼我們可以通過在指令中配置忽略告警資訊,或者直接使用這裡介紹的`pytest.ini`來忽略相應的告警資訊:
```bash
# pytest.ini
[pytest]
filterwarnings =
ignore::PendingDeprecationWarning
```
在當前目錄下的`ini`配置檔案中,我們添加了`PendingDeprecationWarning`作為忽略項,然後我們再回頭看一下上述用例的測試結果:
```bash
[dechin@dechin-manjaro pytest]$ py.test
=========================================== test session starts ============================================
platform linux -- Python 3.8.5, pytest-6.2.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/dechin/projects/2021-python/pytest, configfile: pytest.ini
plugins: cov-2.11.1, metadata-1.11.0, html-3.1.1
collected 1 item
test_random_number.py . [100%]
============================================ 1 passed in 0.50s =============================================
```
這裡返回的結果中就沒有告警資訊了。
## pytest生成html格式報告
為了更好的展現測試的結果,這裡我們需要先安裝一個元件`pytest-html`:
```bash
[dechin@dechin-manjaro pytest]$ python3 -m pip install pytest-html
Collecting pytest-html
Downloading pytest_html-3.1.1-py3-none-any.whl (14 kB)
Collecting pytest-metadata
Downloading pytest_metadata-1.11.0-py2.py3-none-any.whl (10 kB)
Requirement already satisfied: pytest!=6.0.0,>=5.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest-html) (6.2.1)
Requirement already satisfied: attrs>=19.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (20.3.0)
Requirement already satisfied: py>=1.8.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (1.9.0)
Requirement already satisfied: toml in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (0.10.1)
Requirement already satisfied: packaging in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (20.4)
Requirement already satisfied: pluggy<1.0.0a1,>=0.12 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (0.13.1)
Requirement already satisfied: iniconfig in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest!=6.0.0,>=5.0->pytest-html) (1.1.1)
Requirement already satisfied: six in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest!=6.0.0,>=5.0->pytest-html) (1.15.0)
Requirement already satisfied: pyparsing>=2.0.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest!=6.0.0,>=5.0->pytest-html) (2.4.7)
Installing collected packages: pytest-metadata, pytest-html
Successfully installed pytest-html-3.1.1 pytest-metadata-1.11.0
```
安裝成功後,執行如下指令,可以在當前目錄下生成一個指定檔名的html檔案,如下圖所示,就比較全面且美觀的展示了測試中的資訊:
```bash
[dechin@dechin-manjaro pytest]$ py.test --html=pytest_report.html
=========================================== test session starts ============================================
platform linux -- Python 3.8.5, pytest-6.2.2, py-1.9.0, pluggy-0.13.1
rootdir: /home/dechin/projects/2021-python/pytest, configfile: pytest.ini
plugins: cov-2.11.1, metadata-1.11.0, html-3.1.1
collected 1 item
test_random_number.py . [100%]
--------- generated html file: file:///home/dechin/projects/2021-python/pytest/pytest_report.html ----------
============================================ 1 passed in 0.51s =============================================
```
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228214751932-2143574590.png)
不過在問題數量並不是很多的情況下,直接看命令列輸出也是比較方便的。
## pytest覆蓋率測試
在一個python倉庫中我們有可能有非常多的函式、類和檔案等,為了保障結果的準確性,我們需要能夠給出一個可信的覆蓋率測試的結論,只有當覆蓋率達到100%時,我們才能認為測試工作已經比較全面的考慮。當然,覆蓋率100%的測試,其實並不能保障100%的不出問題,這就是另外的話題了。首先我們又需要補充安裝一個元件`pytest-cov`:
```bash
[dechin@dechin-manjaro pytest]$ python3 -m pip install pytest-cov
Collecting pytest-cov
Downloading pytest_cov-2.11.1-py2.py3-none-any.whl (20 kB)
Collecting coverage>=5.2.1
Downloading coverage-5.4-cp38-cp38-manylinux2010_x86_64.whl (245 kB)
|████████████████████████████████| 245 kB 15 kB/s
Requirement already satisfied: pytest>=4.6 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest-cov) (6.2.1)
Requirement already satisfied: attrs>=19.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (20.3.0)
Requirement already satisfied: packaging in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (20.4)
Requirement already satisfied: iniconfig in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (1.1.1)
Requirement already satisfied: toml in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (0.10.1)
Requirement already satisfied: py>=1.8.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (1.9.0)
Requirement already satisfied: pluggy<1.0.0a1,>=0.12 in /home/dechin/anaconda3/lib/python3.8/site-packages (from pytest>=4.6->pytest-cov) (0.13.1)
Requirement already satisfied: six in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest>=4.6->pytest-cov) (1.15.0)
Requirement already satisfied: pyparsing>=2.0.2 in /home/dechin/anaconda3/lib/python3.8/site-packages (from packaging->pytest>=4.6->pytest-cov) (2.4.7)
Installing collected packages: coverage, pytest-cov
Successfully installed coverage-5.4 pytest-cov-2.11.1
```
然後在當前目錄下執行以下指令:
```bash
[dechin@dechin-manjaro pytest]$ py.test --cov=random_number ./ --cov-report=html
=========================================== test session starts ============================================
platform linux -- Python 3.8.5, pytest-6.2.1, py-1.9.0, pluggy-0.13.1
rootdir: /home/dechin/projects/2021-python/pytest, configfile: pytest.ini
plugins: cov-2.11.1, metadata-1.11.0, html-3.1.1
collected 1 item
test_random_number.py . [100%]
----------- coverage: platform linux, python 3.8.5-final-0 -----------
Coverage HTML written to dir htmlcov
============================================ 1 passed in 0.76s =============================================
```
這裡會提示我們去`htmlcov`目錄下找測試報告,我們開啟相應的`index.html`檔案,效果如下:
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228214850576-396566691.png)
這裡我們看到`random_number.py`檔案的測試覆蓋率為86%,我們可以點開連結檢視剩下未覆蓋的測試是什麼內容:
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228214921707-838032453.png)
原來是main函式中的幾行指令沒有被測試到,一般我們在正式倉庫中,是需要去掉main函式的,如果不是測試檔案的話。
# 使用flake8進行python編碼規範檢查
首先我們還是使用pip來直接安裝`flake8`元件,其集成了PEP8的python編碼規範:
```bash
[dechin@dechin-manjaro pytest]$ python3 -m pip install -U flake8
Requirement already up-to-date: flake8 in /home/dechin/anaconda3/lib/python3.8/site-packages (3.8.4)
Requirement already satisfied, skipping upgrade: mccabe<0.7.0,>=0.6.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8) (0.6.1)
Requirement already satisfied, skipping upgrade: pyflakes<2.3.0,>=2.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8) (2.2.0)
Requirement already satisfied, skipping upgrade: pycodestyle<2.7.0,>=2.6.0a1 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8) (2.6.0)
```
檢視安裝的flake8版本號:
```bash
[dechin@dechin-manjaro pytest]$ flake8 --version
3.8.4 (mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0) CPython 3.8.5 on Linux
```
使用方式較為簡單,在當前目錄下直接執行flake8即可,檢查項會以當前路徑為rootdir,遞迴的進行檢索:
```bash
[dechin@dechin-manjaro pytest]$ flake8
./test_random_number.py:2:1: F401 'pytest' imported but unused
./test_random_number.py:5:1: E302 expected 2 blank lines, found 1
./random_number.py:5:1: E302 expected 2 blank lines, found 1
./random_number.py:15:1: E305 expected 2 blank lines after class or function definition, found 1
./random_number.py:17:10: E211 whitespace before '('
./random_number.py:17:80: E501 line too long (87 > 79 characters)
```
假如我們不想包含測試用例的風格檢查,我們可以在命令列中遮蔽相關檔案,或者建立配置檔案,在配置檔案中遮蔽相關檔案,這裡介紹後者的使用方法:
```bash
# .flake8
[flake8]
exclude = ./test*
```
這個配置的意義在於,將當前目錄下,所有以test開頭的檔案,都將會忽略python編碼規範的檢查,配置檔案支援萬用字元的表達形式。接下來看下最新的執行結果:
```bash
[dechin@dechin-manjaro pytest]$ flake8
./random_number.py:5:1: E302 expected 2 blank lines, found 1
./random_number.py:15:1: E305 expected 2 blank lines after class or function definition, found 1
./random_number.py:17:10: E211 whitespace before '('
./random_number.py:17:80: E501 line too long (87 > 79 characters)
```
我們發現前面出現的關於測試用例中的編碼規範,已經不在這個列表的範圍了。這個列表中的問題我們一般最好是處理下,但是如果遇到一些判斷不需要處理的規範,則同樣可以在配置檔案中新增相應的規範ID,這裡僅作示例使用,前面顯示的編碼規範問題後面都會改。如下所示就是兩個忽略:
```bash
# .flake8
[flake8]
exclude = ./test*
ignore = E302, E305
```
對應的執行結果如下所示:
```bash
[dechin@dechin-manjaro pytest]$ flake8
./random_number.py:17:10: E211 whitespace before '('
./random_number.py:17:80: E501 line too long (87 > 79 characters)
```
我們發現被忽略的問題已經沒有顯示了。flake8還有一個特點,是可以配置`max-complexity`,其採用的基本複雜性計算方法為McCabe度量法,可以參考[這篇部落格](https://blog.csdn.net/t_1007/article/details/53034408)中的介紹內容,這裡就不過多的贅述。為了更加美觀簡明的看到輸出的結果,我們可以補充安裝一個元件`flake8-html`:
```bash
[dechin@dechin-manjaro pytest]$ python3 -m pip install flake8-html
Collecting flake8-html
Downloading flake8_html-0.4.1-py2.py3-none-any.whl (13 kB)
Requirement already satisfied: pygments>=2.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8-html) (2.7.2)
Requirement already satisfied: flake8>=3.3.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8-html) (3.8.4)
Requirement already satisfied: jinja2>=2.9.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8-html) (2.11.2)
Requirement already satisfied: importlib-metadata in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8-html) (2.0.0)
Requirement already satisfied: pycodestyle<2.7.0,>=2.6.0a1 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8>=3.3.0->flake8-html) (2.6.0)
Requirement already satisfied: mccabe<0.7.0,>=0.6.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8>=3.3.0->flake8-html) (0.6.1)
Requirement already satisfied: pyflakes<2.3.0,>=2.2.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from flake8>=3.3.0->flake8-html) (2.2.0)
Requirement already satisfied: MarkupSafe>=0.23 in /home/dechin/anaconda3/lib/python3.8/site-packages (from jinja2>=2.9.0->flake8-html) (1.1.1)
Requirement already satisfied: zipp>=0.5 in /home/dechin/anaconda3/lib/python3.8/site-packages (from importlib-metadata->flake8-html) (3.4.0)
Installing collected packages: flake8-html
Successfully installed flake8-html-0.4.1
```
使用方法如下:
```bash
[dechin@dechin-20n2s01200 pytest]$ flake8 --format=html --htmldir=flake-report
./random_number.py has issues: medium: 4
```
在當前目錄執行後,相關的規範的issue就不會在命令列裡面逐一顯示,都在flake-report目錄下的index.html中可以檢視:
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228234700674-1081519054.png)
我們可以點選進入相應檔案的issue清單中去檢視:
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228234720845-212818278.png)
可以點選每一個issue,展開內容中包含了issue所對應行的程式碼內容:
![](https://img2020.cnblogs.com/blog/2277440/202102/2277440-20210228234743208-1827795154.png)
經過一番修改之後,我們得到的flake8配置檔案和原始碼檔案如下:
```bash
# .flake8
[flake8]
exclude = ./test*
ignore = W391
```
```python
# random_number.py
from projectq import MainEngine
from projectq.ops import H, Measure
def random_number_generator():
eng = MainEngine()
qubit = eng.allocate_qubit()
H | qubit
eng.flush()
Measure | qubit
random_number = int(qubit)
eng.flush(deallocate_qubits=True)
return random_number
if __name__ == '__main__':
random_number = random_number_generator()
print('Random number generated by quantum simulator is:\
{}'.format(random_number))
```
最終我們的目的是使得flake8執行的issue清零:
```bash
[dechin@dechin-manjaro pytest]$ flake8 --format=html --htmldir=flake-report
[dechin@dechin-manjaro pytest]$
```
# 總結概要
本文通過引入一個隨機數生成器的案例,介紹了在量子計算中產生真隨機數的方案,同時給出了量子計算模擬實現。藉此機會也同時介紹了python的單元測試庫pytest的一些常規和擴充套件使用方法,以及python的編碼規範測試庫flake8的基本使用方法,希望能夠對大家有所啟發以及幫助。
# 版權宣告
本文首發連結為:https://www.cnblogs.com/dechinphy/p/random_number_test.html
作者ID:DechinPhy
更多原著文章請參考:https://www.cnblogs.com/dechinphy/
# 參考連結
1. https://cn.bing.com/images/search?view=detailV2&ccid=X1pIP1mm&id=0CF2CDDD1C700A051F3FEB4701669068CE05B9FA&thid=OIP.X1pIP1mmVKohO5UC1CvbuQHaED&mediaurl=https%3a%2f%2fth.bing.com%2fth%2fid%2fR5f5a483f59a654aa213b9502d42bdbb9%3frik%3d%252brkFzmiQZgFH6w%26riu%3dhttp%253a%252f%252fwww.supernovapcrepair.co.uk%252fimages%252fquantum%2bsuperposition.png%26ehk%3dEt3zyrD9NqYgaMFwpPb%252bcZAohbR0ERpeRfCEkgKy6i0%253d%26risl%3d%26pid%3dImgRaw&exph=199&expw=363&q=quantum+superposition&simid=608026555008484117&ck=E74E3E03947D89427ED1A5352402AADB&selectedIndex=3&FORM=IRPRST&aja