PythonのLogging

シンプルなログ出力はお馴染みのprint文

print("I am the simplest log.")

ファイル出力、メール送信、HTTP通信など動作ログをよりフレキシブルに出力したい場合にはloggingモジュールを使用してログを出力する。

### ログレベル
DEBUG, INFO, WARNING, ERROR, CRITICAL

出力

import logging 

logging.info("info log")
logging.warning("warning log")

$ python3 test.py
WARNING:root:warning log

info はコマンドラインに出力されない
loggerオブジェクトを取得してログを出力する

import logging 

logger = logging.getLogger("sample")
logger.info("info log")
logger.warning("warning log")

$ python3 test.py
warning log

import logging 

logger = logging.getLogger("sample")
logger.setLevel(logging.DEBUG)
logger.info("info log")
logger.warning("warning log")

### ハンドラ
StreamHandler, FileHandler, SMTPHandler, HTTPHandlerがある

import logging 

logger = logging.getLogger("sample")
logger.setLevel(logging.DEBUG)


st_handler = logging.StreamHandler()

logger.addHandler(st_handler)
logger.info("info log")
logger.warning("warning log")

handlerで指定することでログ出力をカスタマイズできる。

Python stackのpopとpush

class MyStack:
    def __init__(self):
        self.stack = []
    
    def push(self, item):
        self.stack.append(item)

    def pop(self):
        pass

mystack = MyStack()
mystack.push(0)
mystack.push(1)
mystack.push(2)
print(mystack.stack)

$ python3 test.py
[0, 1, 2]

pop

    def pop(self):
        result = self.stack[-1]
        del self.stack[-1]
        return result

print(mystack.pop())
print(mystack.pop())

取り出して削除なので、[-1]の後にdelを実行している。
上記と同じことをpop()と書くことができる。

    def pop(self):
        return self.stack.pop()

stackが0の場合があるので、例外処理も書かなければならない。

    def pop(self):
        if len(self.stack) == 0:
            return None
        return self.stack.pop()

PythonのBytesIO

BytesIOはメモリ上でバイナリデータを扱うための機能
同様な機能としてStringIO, cStringIOがある

import io
import urllib.request
from PIL import Image

url = "https://www.python.org/static/img/python-logo@2x.png"
img_in = urllib.request.urlopen(url).read()
img_bin = io.BytesIO(img_in)
img = Image.open(img_bin)
img.save("logo.png","PNG")
print(img_bin.getvalue())

Pythonのstream

I/O : 入出力input/outputのこと
stream: データが流れる通り道

Pythonおいてストリームを作り簡単な方法はファイルをopenすること
読み取りのストリームにはread(), tell(), seekなどのインターフェイスが用意されている
tellは読み取り位置取得、seekは読み取り位置変更

text_file.txt
1234567890abcdefg

f = open("text_file.txt", "r")
print("tell 1 ->", f.tell())

first4 = f.read(4)
print("first4 ->", first4)
print("tell2 ->", f.tell())
f.seek(10)
last = f.read()
print("last ->", last)
f.close()

$ python3 test.py
tell 1 -> 0
first4 -> 1234
tell2 -> 4
last -> abcdefg

Python @classmethodのcls

クラスメソッドの第1引数はclsで、クラス自身を示す

import datetime

class Reserve:

    dt_now = datetime.datetime.now()

    def __init__(self, dep, dest, time):
        self.dep = dep
        self.dest = dest
        self.time = time

    def plan(self):
        print(f"予約内容は、出発地:{self.dep}、目的地:{self.dest}、出発時間:{self.time}です")

    @classmethod
    def clock(cls):
        print(f"只今の時刻は、{cls.dt_now}です")


osakaTrip = Reserve("東京","大阪","16時")
osakaTrip.plan()
Reserve.clock()

$ python3 test.py
予約内容は、出発地:東京、目的地:大阪、出発時間:16時です
只今の時刻は、2023-11-16 02:47:03.822162です

print(f”只今の時刻は、{dt_now}です”) とすると、以下のようにエラーになります。
Traceback (most recent call last):
File “/home/vagrant/dev/test/test.py”, line 23, in
Reserve.clock()
File “/home/vagrant/dev/test/test.py”, line 18, in clock
print(f”只今の時刻は、{dt_now}です”)
NameError: name ‘dt_now’ is not defined

Pythonのhash関数

print(hash("abc"))
print(hash("def"))
print(hash(123))
print(hash(123.0))
print(hash(-123))
print(hash("abc"))

$ python3 test.py
-6216428559771217202
-5554558427243961036
123
123
-123
-6216428559771217202

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

バイトを受け取り、リトルエンディアンとして解釈して数値を返す関数

def little_endian_to_int(b):

    return int.from_bytes(b, 'little')

数字を受け取り、リトルエンディアンとしてバイトを返却

def int_to_little_endian(n, length):

    return n.to_bytes(length, 'little')

バイト数も256とか指定するのではなく、引数lengthとして受け付ける。また、数字はiよりnの方がベター