Python | with 文が使える関数を作る

with 文が使える関数をつくる

yield 式のところで with ブロックの内容が実行される

#with_openthebook.py
from contextlib import contextmanager


class Book():
    def __init__(self):
        self.contents = ''
        self.isopen = False

    def open(self):
        self.isopen = True
        print('本は開かれた')
        return self

    def write(self, contents):
        if self.isopen:
            print('本に記録した')
            self.contents = contents
        else:
            print('本は開かれていない\n')

    def read(self):
        if self.isopen:
            print('本には次のように記録されていた')
            print(self.contents)
        else:
            print('本は開かれていない\n')

    def close(self):
        self.isopen = False
        print('本は閉じられた\n')


@contextmanager
def openthebook(book=None):
    if book is None:
        book = Book()
    book.open()
    try:
        yield book
    finally:
        book.close()


if __name__ == '__main__':
    with openthebook() as book:
        book.write('ばなな')
    book.read()
    with openthebook(book):
        book.read()

これを実行すると次のように表示される。

$ python with_openthebook.py
本は開かれた
本に記録した
本は閉じられた

本は開かれた
本には次のように記録されていた
ばなな
本は閉じられた

本は開かれていない

Python | pdb 対話的デバッガ

対話的デバッガ

デバッグしたい部分に次の一文を挿入

import pdb; pdb.set_trace()

(Pdb) プロンプトのコマンド(の例)

プログラムを調べるコマンド
  • w(here)   スタックトレースを表示、矢印は現在のフレームを表す
  • u(p)   スコープを関数の呼び出し元に移す (older frame)
  • d(own)   スコープを一段下に移す (newer frame)
プログラム実行を制御するコマンド
  • s(tep)   次の行まで実行、関数が呼ばれた場合は関数内で一時停止
  • n(ext)   次の行に達するか、関数が返るまで実行を続行
  • r(eturn)   現在の関数が帰るまで実行
  • c(ontinue)   次のブレークポイントまで実行


[参考文献]
27.3. pdb — The Python Debugger — Python 3.5.2 documentation

Effective Python ―Pythonプログラムを改良する59項目

Effective Python ―Pythonプログラムを改良する59項目

Python | python コードのテスト

unittest を使う

# utils.py
def to_hex(integer, length, byteorder, *, signed=False):
    b = integer.to_bytes(length, byteorder, signed=signed)
    lst = ['{:02X}'.format(x) for x in b]
    return ''.join(lst)


# test_to_hex.py
from unittest import TestCase, main
from utils import to_hex


class UtilsTestCase(TestCase):
    def test_to_hex_1byte(self):
        self.assertEqual('9C', to_hex(-100, 1, 'big', signed=True))

    def test_to_hex_2byte_little(self):
        self.assertEqual('18FC', to_hex(-1000, 2, 'little', signed=True))

    def test_to_hex_2byte_big(self):
        self.assertEqual('FC18', to_hex(-1000, 2, 'big', signed=True))

    def test_to_hex_1byte_unsigned(self):
        self.assertEqual('64', to_hex(100, 1, 'little'))

    def test_to_hex_2byte_unsigned_little(self):
        self.assertEqual('E803', to_hex(1000, 2, 'little'))

    def test_to_hex_2byte_unsigned_big(self):
        self.assertEqual('03E8', to_hex(1000, 2, 'big'))

    def test_to_hex_not_int(self):
        self.assertRaises(AttributeError,
                          to_hex, object(), 2, 'big', signed=True)

    def test_to_hex_overflow(self):
        self.assertRaises(OverflowError,
                          to_hex, -1000, 1, 'big', signed=True)

    def test_to_hex_overflow2(self):
        self.assertRaises(OverflowError,
                          to_hex, -1000, 2, 'big', signed=False)


if __name__ == '__main__':
    main()

Python | 2の補数 (signed) int ⇔ bytes ⇔ str (16進文字列)

(signed) int → bytes

int.to_bytes を使う
>>> (-100).to_bytes(1, byteorder='little', signed=True)
b'\x9c'

>>> (-1000).to_bytes(2, 'little', signed=True)
b'\x18\xfc'

>>> (-1000).to_bytes(2, 'big', signed=True)
b'\xfc\x18'
struct.pack を使う
>>> import struct
>>> struct.pack('b', -100)
b'\x9c'

>>> strckt.pack('h', -1000)  # little endian
b'\x18\xfc'

>>> strckt.pack('>h', -1000)  # big endian
b'\xfc\x18'

bytes → str (16進文字列)

>>> b = b'\x9c'
>>> '{:02X}'.format(b[0])
'9C'

>>> b = b'\xfc\x18'
>>> '{:02X}{:02X}'.format(b)
'FC18'

>>> lst = ['{:02X}'.format(x) for x in b]
>>> lst
['FC', '18']
>>> ''.join(lst)    # big endian
'FC18'

>>> lst.reverse()
>>> lst
['18', 'FC']
>>> ''.join(lst)    # little endian
'18FC'

str (16進文字列) → bytes

>>> n = int('9C', 16)
>>> n.to_bytes(1, byteorder='big')
b'\x9c'

>>> n = int('FC18', 16)
>>> n.to_bytes(2, byteorder='big')
b'\xfc\x18'

>>> n = int('18FC', 16)
>>> n.to_bytes(2, byteorder='little')
b'\xfc\x18'

bytes → (signed) int

int.from_bytes を使う
>>> int.from_bytes(b'\x9c', byteorder='big', signed=True)
-100

>>> int.from_bytes(b'\xfc\x18', 'big', signed=True)
-1000

>>> int.from_bytes(b'\x18\xfc', 'little', signed=True)
-1000
struct.unpack を使う
>>> import struct
>>> struct.unpack('b', b'\x9c')[0]
-100

>>> struct.unpack('>h', b'\xfc\x18')[0]  # big endian
-1000

>>> struct.unpack('h', b'\x18\xfc')[0]  # little endian
-1000

Python | 2の補数のビットパターンを文字列で得る方法

str.format を使う
>>> '{:08b}'.format(-100 & 0xff)
'10011100'

>>> '{:02X}'.format(-100 & 0xFF)
'9C'

>>> '{:02X}'.format(-1000 & 0xFFFF)
'FC18'
int.to_bytes を使う
>>> b = (-100).to_bytes(1, byteorder='little', signed=True)
>>> b
b'\x9c'
>>> '{:02X}'.format(b[0])
'9C'

>>> b = (-1000).to_bytes(2, 'little', signed=True)
>>> b
b'\x18\xfc'
>>> '{:02X}{:02X}'.format(*b)
'18FC'

>>> b = (-1000).to_bytes(2, 'big', signed=True)
>>> b
b'\xfc\x18'
>>> lst = ['{:02X}'.format(x) for x in b]
>>> lst
['FC', '18']
>>> ''.join(lst)
'FC18'
struct を使う
>>> import struct
>>> b = struct.pack('b', -100)
>>> b
b'\x9c'
>>> '{:02X}'.format(b[0])
'9C'

>>> b = strckt.pack('h', -1000)
>>> b
b'\x18\xfc'
>>> '{:02X}{:02X}'.format(*b)
'18FC'

>>> b = strckt.pack('>h', -1000)
>>> b
b'\xfc\x18'
>>> lst = ['{:02X}'.format(x) for x in b]
>>> lst
['FC', '18']
>>> ''.join(lst)
'FC18'