pythonのdigest()とhexdigest()

digest()はバイト列、hexdigest()は16進数を返却する

import hashlib 

print(hashlib.sha256(b'test').digest())
print(hashlib.sha256(b'test').hexdigest())

$ python3 test.py
b’\x9f\x86\xd0\x81\x88L}e\x9a/\xea\xa0\xc5Z\xd0\x15\xa3\xbfO\x1b+\x0b\x82,\xd1]l\x15\xb0\xf0\n\x08′
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

pythonでdivmod

Pythonでは //で商、%で余りだが、divmodで両方を出力する。

q = 13 // 4
mod = 13 % 4
print(q, mod)

q, mod = divmod(17, 7)
print(q, mod)

$ python3 test.py
3 1
2 3

pythonのbytes型

bytesはバイナリデータを扱うバイト型

str1 = "高島屋"
enc_str1 = str1.encode()

print(f"{str1}:{enc_str1}")
print(f"type: {type(enc_str1)}")

print(f"高: {hex(ord('高'))}")
print(f"島: {hex(ord('島'))}")
print(f"屋: {hex(ord('屋'))}")

$ python3 test.py
高島屋:b’\xe9\xab\x98\xe5\xb3\xb6\xe5\xb1\x8b’
type:
高: 0x9ad8
島: 0x5cf6
屋: 0x5c4b

バイト型はb’で囲まれる
\xは続く文字列

Pythonのクラスメソッド(@classmethod)

クラスにくっついている関数のようなもので、インスタンス化していないクラスのものから呼び出せる。
メソッドに@classmethodと付けることでクラスメソッドにできる。

class A:

    def test_method():
        print("test")

    @classmethod
    def my_cls_method(cls):
        print("hello")

A.my_cls_method()
A.test_method()

– 第一引数でクラスが取得できる(インスタンスメソッドは第一引数が必ずselfになる)
– クラスの中にあるので、クラスをインポートすれば使える
– クラスメソッドを使わずに関数として書くこともできるが、クラスメソッドの場合は、インポートできて、まとめて管理できる

class Item:
    def __init__(self, id, name):
        self.id = id
        self.name = name

    @classmethod
    def retrieve_from_api(cls, id):
        res = requests.get(f"https://api.example.com/items/{id}")
        data = res.json()
        return cls(id, data["name"])

Pythonのビッグエンディアンとリトルエンディアン

import binascii

hex_b = 'f0148c'
bytes_be = binascii.unhexlify(hex_b)
bytes_le = bytes_be[::-1]
hex_le = binascii.hexlify(bytes_le).decode()
print(hex_le)
import sys

def dump(data):
    print(data)

    a = int.from_bytes(data, byteorder='big')
    b = int.from_bytes(data, byteorder='little')
    c = int.from_bytes(data, byteorder=sys.byteorder)
    print(a, hex(a))
    print(b, hex(b))
    print(c, hex(c))

dump(b'\x01\x02')
dump(b'\x11\x12\x13\x14\x15\x16\x17\x18\x19')

$ python3 test.py
b’\x01\x02′
258 0x102
513 0x201
513 0x201
b’\x11\x12\x13\x14\x15\x16\x17\x18\x19′
314897056051100063769 0x111213141516171819
462904482303900324369 0x191817161514131211
462904482303900324369 0x191817161514131211

Python super().__init__()の使い方

継承元のコンストラクタをオーバラーライドする

class Parent:
    def __init__(self, a, b):
        self.a = a 
        self.b = b
    
    def w(self):
        print(self.b)

class Child(Parent):
    def w(self):
        return super().w()

child = Child(0, 'hello')
child.w()

サブクラスで__init__を定義すると親クラスの上書きされてしまう。

class A:
    def __init__(self, name):
        self.name = name 

class B(A):
    def __init__(self, name, mail):
        super().__init__(name)
        self.mail = mail

b = B("yamada", "gmail")
b.name
class Parent:
    def __init__(self, name, age):
        self.name = name 
        self.age = age 

    def my_name(self):
        print("名前は" + self.name + "。年齢は" + str(self.age) + "歳。")

class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name, age)

yamada = Child("yamada", 20)
yamada.my_name()

Python unittestのTextTestRunner().runを理解する

$ sudo apt install tree
$ tree
.
├── other.py
├── suite.py
└── test.py

test.py

import unittest

class MyTest(unittest.TestCase):
    def test_mytest_01(self):
        print("test_mytest_01 is called")
        one = 1
        self.assertEqual(one, 1, "one is 1")

other.py

import unittest

class OhterTest(unittest.TestCase):
    def test_other_01(self):
        print("test_mytest_01 is called")
        two = 2
        self.assertEqual(two, 2, "two is 2")

suite.py

import unittest

import test
import other

def suite():
    test_suite = unittest.TestSuite()
    test_suite.addTest(unittest.makeSuite(test.MyTest))
    test_suite.addTest(unittest.makeSuite(other.OhterTest))
    return test_suite

if __name__ == "__main__":
    mySuite = suite()
    unittest.TextTestRunner().run(mySuite)

$ python3 suite.py
test_mytest_01 is called
.test_mytest_01 is called
.
———————————————————————-
Ran 2 tests in 0.000s

OK

addTestとして、unittest.TextTestRunner().run() でテストを実行する

Pythonでunittest

unittestモジュールをimportし、unittest.TestCaseクラスを継承したテストクラスを作成する。その際、テストメソッドはtestという単語で始まる必要がある。

import uittest
from my_module import my_function

class MyTest(unittest.TestCase):
    def test_my_function(self):
        result = my_function(2)
        self.assertEqual(result, 4)

if __name__ == '__main__':
    unittest.main()

具体例

import unittest

def add(a, b):
    return a + b

class TestAddFunction(unittest.TestCase):

    def test_add_integer(self):
        result = add(2, 3)
        self.assertEqual(result, 5)

    def test_add_floats(self):
        result = add(2.5, 3.5)
        self.assertAlmostEqual(result, 6.0, places=2)

    def test_add_strings(self):
        result = add("Hello, ", "world!")
        self.assertEqual(result, "Hello, world!")

if __name__ == '__main__':
    unittest.main()

$ python3 test.py

———————————————————————-
Ran 3 tests in 0.000s

OK

return a + b + 1 とすると、
$ python3 test.py
FFE
======================================================================
ERROR: test_add_strings (__main__.TestAddFunction)
———————————————————————-
Traceback (most recent call last):
File “/home/vagrant/dev/blockchain/test.py”, line 17, in test_add_strings
result = add(“Hello, “, “world!”)
File “/home/vagrant/dev/blockchain/test.py”, line 4, in add
return a + b + 1
TypeError: can only concatenate str (not “int”) to str

======================================================================
FAIL: test_add_floats (__main__.TestAddFunction)
———————————————————————-
Traceback (most recent call last):
File “/home/vagrant/dev/blockchain/test.py”, line 14, in test_add_floats
self.assertAlmostEqual(result, 6.0, places=2)
AssertionError: 7.0 != 6.0 within 2 places (1.0 difference)

======================================================================
FAIL: test_add_integer (__main__.TestAddFunction)
———————————————————————-
Traceback (most recent call last):
File “/home/vagrant/dev/blockchain/test.py”, line 10, in test_add_integer
self.assertEqual(result, 5)
AssertionError: 6 != 5

———————————————————————-
Ran 3 tests in 0.000s

FAILED (failures=2, errors=1)

Test Classの中で、setUp, tearDownを入れると、テストの実行前後でそれぞれ実行される。

class TestAddFunction(unittest.TestCase):

    def setUp(self):
        print("setUp() called")

    def test_add_integer(self):
        result = add(2, 3)
        self.assertEqual(result, 5)

    def test_add_floats(self):
        result = add(2.5, 3.5)
        self.assertAlmostEqual(result, 6.0, places=2)

    def test_add_strings(self):
        result = add("Hello, ", "world!")
        self.assertEqual(result, "Hello, world!")

    def tearDown(self):
        print("tearDown() called")