Python のスニペット集

このページは、Python (3) のスニペットなどをまとめる予定のページです。

目次

注意

  • コードのライセンスは CC0 (クレジット表示不要、改変可、商用可) です。

スニペット

演算子

条件演算子

x が None なら空文字列を代入する
x = 'a'
a = x if x is not None else ''

反復

for i in range(1, 10):
    print(i) # 1~9

デコレータ

関数の実行前と後に処理を行う例
def trace(f):
    import time
    def decorator(*args, **kwargs):
        print(f'---------- start {f.__name__} (args={args}, kwargs={kwargs}) ----------')
        start = time.perf_counter()
        f(*args, **kwargs)
        t = time.perf_counter() - start
        print(f'---------- end   {f.__name__} (args={args}, kwargs={kwargs}) time: {t:.10f} ----------')

    return decorator

@trace
def func(a, b, c):
    print(a, b, c)

func(1, 2, 3)

# 結果
# ---------- start func (args=(1, 2, 3), kwargs={}) ----------
# 1 2 3
# ---------- end   func (args=(1, 2, 3), kwargs={}) time: 0.0000020005 ----------

文字列

フォーマット

フォーマット文字列
a = 1
b = 2
s = f'a = {a}, b = {b}'
書式化演算子
a = 1
b = 2
s = 'a = %d, b = %02d' % (a, b) # 'a = 1, b = 02'
テンプレート文字列
# from string import Template

s = Template('a = $a, b = $b')
s.substitute({'a': 1, 'b': 2})

パディング

左0埋め
a = 1
s1 = str(1).zfill(4) # 0001
s2 = str(1).rjust(4, '0') # 0001
s3 = format(a, '04') # 0001
s4 = '{0:04}'.format(a) # 0001
s5 = '%04d' % a # 0001
右0埋め
a = 1
s = str(1).ljust(4, '0') # 1000
s3 = format(a, '<04') # 1000
s4 = '{0:<04}'.format(a) # 1000

文字列の検索

中間一致
s = 'test string'
b = 'str' in s
前方一致
s = 'test string'
b = s.startswith('test')
後方一致
s = 'test string'
b = s.endswith('ing')

数値変換

整数
s = '123'
try:
    n = int(s)
except:
    n = 0
小数点数
s = '123.45'
try:
    n = float(s)
except:
    n = 0

list

内包記法

list1 = [{'year': 2022, 'value':100}, {'year': 2023, 'value':200}, {'year': 2024, 'value':300}]
years = [it['year'] for it in list1] # [2022, 2023, 2024]

要素の削除

del
list1 = [1, 2, 3]
del list1[1]
pop
list1 = [1, 2, 3]
list1.pop(1)

ソート

data = [
    { 'id': 1, 'name': '山田太郎' },
    { 'id': 3, 'name': '斎藤花子' },
    { 'id': 2, 'name': '鈴木次郎' },
]
data2 = sorted(data, key=lambda x: x['id']) # [{'id': 1, 'name': '山田太郎'}, {'id': 2, 'name': '鈴木次郎'}, {'id': 3, 'name': '斎藤花子'}]
data3 = sorted(data, key=lambda x: x['id'], reverse=True) # [{'id': 3, 'name': '斎藤花子'}, {'id': 2, 'name': '鈴木次郎'}, {'id': 1, 'name': '山田太郎'}]

dict

キーの存在確認

キーの存在確認 (in)
d1 = {'a': 1, 'b': 2}
if 'a' in d1:
    print(d1['a'])

マージ

d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'd': 4}

d3 = {**d1, **d2} # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
d4 = {**d1, 'e': 5, 'f': 6} # {'a': 1, 'b': 2, 'e': 5, 'f': 6}
Python 3.9 以降
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'd': 4}

d3 = d1 | d2

zip

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values)) # {'a': 1, 'b': 2, 'c': 3}

要素の削除

pop (第2引数でキーが無かった時の値を指定するとキーが無くてもエラーにならない)
d = {'a': 1}
d.pop('a', None)
del (キーが無いと KeyError)
d = { 'a': 1 }
del d['a']

一部のキーのみの dict を取得

d = {'a': 1, 'b': 2, 'c': 3}
keys = ['a', 'b']
d2 = {k:v for k, v in d.items() if k in keys} # {'a': 1, 'b': 2}

日時

現在日時

# from datetime import datetime
dt = datetime.now()
タイムゾーン指定 (UTC。datetime.utcnow() だと tzinfo が設定されません)
# from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
タイムゾーン指定 (JST +9:00)
# from datetime import datetime, timezone, timedelta
jst = timezone(timedelta(hours=+9))
dt = datetime.now(jst)
タイムゾーン指定 (あとから)
# from datetime import datetime, timezone
dt = datetime.now()
tz = timezone.utc
dt2 = dt.astimezone(tz)

フォーマット

strftime()
YYYY-MM-DD HH:MM:SS
# from datetime import datetime
dt = datetime(2021, 1, 2, 3, 4, 5)
s = dt.strftime("%Y-%m-%d %H:%M:%S") # 2021-01-02T03:04:05
isoformat()
YYYY-MM-DDTHH:MM:SS
# from datetime import datetime
dt = datetime(2021, 1, 2, 3, 4, 5)
s = dt.isoformat() # 2021-01-02T03:04:05
YYYY-MM-DD HH:MM:SS
# from datetime import datetime
dt = datetime(2021, 1, 2, 3, 4, 5)
s = dt.isoformat(' ') # 2021-01-02 03:04:05
分→時間
m = 90
'%d:%02d' % divmod(m, 60) # 1:30 (h:mm)
'%02d:%02d' % divmod(m, 60) # 01:30 (hh:mm)

m = 1470
'%d:%02d' % divmod(m, 60) # 24:30 (h:mm)
'%02d:%02d' % divmod(m, 60) # 24:30 (hh:mm)

時間の切り捨て

# from datetime import datetime

dt = datetime.now()
dt2 = dt.replace(hour=0, minute=0, second=0, microsecond=0)

日の演算 (加算など)

日の加算
# from datetime import datetime, timedelta

dt = datetime(2021, 1, 31)
dt2 = dt + timedelta(days=1) # 2021-02-01

月の演算 (加算など)

月の加算
# from datetime import datetime
# from dateutil.relativedelta import relativedelta

dt = datetime(2021, 1, 31)
dt2 = dt + relativedelta(months=1) # 2021-02-28
月末
# from datetime import datetime
# from dateutil.relativedelta import relativedelta

dt = datetime(2021, 2, 15)
dt2 = dt + relativedelta(day=1, months=1, days=-1) # 2021-02-28

経過時間

# import time
start = time.time()
# 処理 ...
elapsed = time.time() - start

正規表現

英数
# import re
s = 'abc123'
result = re.fullmatch('[a-zA-Z0-9]+', s)
英数記号
# import re
s = 'abc123!'
symbol = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
result = re.fullmatch('[a-zA-Z0-9%s]+' % re.escape(symbol), s)

UUID

# import uuid
uuid_str = str(uuid.uuid1())

ファイル

タイムスタンプ変更

# import time
# import os

t = time.mktime((2019, 1, 1, 0, 0, 0, 0, 0, 0)) # 2019-01-01 00:00:00
os.utime('file.txt', (t, t))

sleep

1秒待つ
# import time
time.sleep(1)

パス

実行パスからの相対パス解決

# import pathlib
p = str(pathlib.Path(__file__).parent.joinpath('path/to/file.txt')) # /example/test/main.py で動作している場合 /example/test/path/to/file.txt

URL

パス結合

# from urllib.parse import urljoin
p = urljoin('https://exmaple.com/api/', 'path/to/file.txt')

JSON

エンコード

文字列出力
# import json
data = {'a': 1, 'b': 2, 'c': 'テスト'}
s = json.dumps(data)
ファイル出力 (マルチバイト文字をエスケープしない)
# import json
data = {'a': 1, 'b': 2, 'c': 'テスト'}
with open('/path/to/data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=4, ensure_ascii=False)

デコード

文字列から
# import json
s = '[1,2,3]'
data = json.loads(s)
ファイルから
# import json
with open('/path/to/data.json', 'r') as f:
    data = json.load(f)

INI

読み込み

ini ファイルの例 (settings.ini)
[section1]
value1=1
# import configparser

config = configparser.ConfigParser()
config.read('settings.ini')
value1 = config['section1']['value1']

書き込み

# import configparser

config = configparser.ConfigParser()
config['a'] = {}
config['a']['b'] = "c"
with open('settings.ini', 'w') as f:
   config.write(f)

HTTP

GET

# import urllib.request

url = 'https://example.com/'
headers = {
    'Accept-Language': 'ja',
}
data = {
    'foo': 1
}
req = urllib.request.Request(f'{url}?{urllib.parse.urlencode(data)}', None, headers)
with urllib.request.urlopen(req) as res:
    body = res.read().decode('utf-8')
    print(body)

GET (SSL の検証無効化)

# import urllib.request
# import ssl

url = 'https://example.com/'
headers = {
    'Accept-Language': 'ja',
}
data = {
    'foo': 1
}
req = urllib.request.Request(f'{url}?{urllib.parse.urlencode(data)}', None, headers)
context = ssl.create_default_context() # SSL のコンテキストを生成
context.check_hostname = False # ホスト名のチェックを無効化
context.verify_mode = ssl.CERT_NONE # 検証無効化
with urllib.request.urlopen(req, context=context) as res:
    body = res.read().decode('utf-8')
    print(body)
  • POST の場合も同じように urlopen() にコンテキストを渡します。

GET (エラー制御)

url = 'https://example.com/'
headers = {
    'Accept-Language': 'ja',
}
data = {
    'foo': 1
}

try:
    req = urllib.request.Request(f'{url}?{urllib.parse.urlencode(data)}', None, headers)
    with urllib.request.urlopen(req) as res:
        body = res.read().decode('utf-8')
        print(body)
except urllib.error.HTTPError as e:
    # e.code に数値型でステータスコードが格納されている
    print(e)

POST

# import urllib.request

url = 'https://example.com/'
headers = {
    'Accept-Language': 'ja',
}
data = {
    'foo': 1
}
req = urllib.request.Request(url, urllib.parse.urlencode(data).encode(), headers)
with urllib.request.urlopen(req) as res:
    body = res.read().decode('utf-8')
    print(body)

POST (JSON)

# import urllib.request
# import json

url = 'https://example.com/'
headers = {
    'Content-Type': 'application/json',
}
data = {
    'foo': 1
}
req = urllib.request.Request(url, json.dumps(data).encode(), headers)
with urllib.request.urlopen(req) as res:
    body = res.read().decode('utf-8')
    resData = json.loads(body)
    print(resData)

TCP

データの受信 (クライアント側)

socket.create_connection()
# import socket

host = '127.0.0.1'
port = 4000
timeout = 5
with socket.create_connection((host, port), timeout) as sock:
    res = sock.recv(1024)
    print(repr(res))
sock.connect()
# import socket

host = '127.0.0.1'
port = 4000
timeout = 5
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
    sock.settimeout(timeout)
    sock.connect((host, port))
    res = sock.recv(1024)
    print(repr(res))

ログ

ロガーの設定 (コンソール)

# import logging
# import logging.handlers

loglevel = logging.DEBUG  # ログレベル
logger = logging.getLogger(__name__)  # ロガー生成

logger.setLevel(loglevel)  # ログレベル設定
handler = logging.StreamHandler()  # 出力ハンドラ (コンソール)
handler.setLevel(loglevel)  # ログレベル設定
handler.setFormatter(logging.Formatter(
    '%(asctime)s %(name)s [%(levelname)s] %(message)s'))  # 出力フォーマット設定
logger.addHandler(handler)  # 出力ハンドラのセット

ロガーの設定 (ファイル)

# import logging
# import logging.handlers

loglevel = logging.DEBUG  # ログレベル
logger = logging.getLogger(__name__)  # ロガー生成

logger.setLevel(loglevel)  # ログレベル設定
handler = logging.FileHandler('log.log')  # 出力ハンドラ (ファイル)
handler.setLevel(loglevel)  # ログレベル設定
handler.setFormatter(logging.Formatter(
    '%(asctime)s %(name)s [%(levelname)s] %(message)s'))  # 出力フォーマット設定
logger.addHandler(handler)  # 出力ハンドラのセット

ロガーの設定 (ファイル + ローテート)

log.log にログ出力 (古いログは log.log.YYYYMMDD に移動)
# import logging
# import logging.handlers

loglevel = logging.DEBUG  # ログレベル
logger = logging.getLogger(__name__)  # ロガー生成

logger.setLevel(loglevel)  # ログレベル設定
handler = logging.handlers.TimedRotatingFileHandler('log.log')  # 出力ハンドラ (ファイル)
handler.suffix = "%Y%m%d" # ログの後ろにセットする日付フォーマット
handler.setLevel(loglevel)  # ログレベル設定
handler.setFormatter(logging.Formatter(
    '%(asctime)s %(name)s [%(levelname)s] %(message)s'))  # 出力フォーマット設定
logger.addHandler(handler)  # 出力ハンドラのセット

ロガーの設定 (設定ファイルから設定)

設定ファイル (logconfig.json)
{
    "version": 1,
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "DEBUG",
            "formatter": "custom"
        },
        "file": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "level": "DEBUG",
            "filename": "log.log",
            "when": "MIDNIGHT",
            "formatter": "custom"
        }
    },
    "formatters": {
        "custom": {
            "format": "%(asctime)s %(name)s [%(levelname)s] %(message)s"
        }
    },
    "root": {
        "handlers": ["console", "file"],
        "level": "DEBUG"
    }
}
# import logging
# import logging.config
# import json

with open('logconfig.json') as f:
    config = json.load(f)

logging.config.dictConfig(config)
logger = logging.getLogger(__name__)

ロガーの設定 (設定ファイルから設定 + カスタムハンドラ)

設定ファイル (logconfig.json。file.class を独自のハンドラクラスにしています)
{
    "version": 1,
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "DEBUG",
            "formatter": "custom"
        },
        "file": {
            "class": "logging.handlers.CustomTimedRotatingFileHandler",
            "level": "DEBUG",
            "filename": "log.log",
            "when": "MIDNIGHT",
            "formatter": "custom"
        }
    },
    "formatters": {
        "custom": {
            "format": "%(asctime)s %(name)s [%(levelname)s] %(message)s"
        }
    },
    "root": {
        "handlers": ["console", "file"],
        "level": "DEBUG"
    }
}
# import logging
# import logging.config
# import re
# import json

class CustomTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    """独自のハンドラクラスです。ファイル形式を log.log.YYYY-MM-DD などから log.YYYYMMDD.log に変更します。
    """

    def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None):
        logging.handlers.TimedRotatingFileHandler.__init__(self, filename, when, interval,
                                                           backupCount, encoding, delay, utc, atTime)

        if self.when == 'S':
            self.suffix = "%Y%m%d%H%M%S"
        elif self.when == 'M':
            self.suffix = "%Y%m%d%H%M"
        elif self.when == 'H':
            self.suffix = "%Y%m%d%H"
        elif self.when == 'D' or self.when == 'MIDNIGHT':
            self.suffix = "%Y%m%d"
        elif self.when.startswith('W'):
            self.suffix = "%Y%m%d"

        def namer(default_name):
            return re.sub(r'log\.([0-9]+)', r'\1.log', default_name)
        self.namer = namer


logging.handlers.CustomTimedRotatingFileHandler = CustomTimedRotatingFileHandler


with open('logconfig.json') as f:
    config = json.load(f)

logging.config.dictConfig(config)
logger = logging.getLogger(__name__)

ロガーの使用

# logger は上記で作成したロガーです

logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')
try:
    raise Exception("exception")
except Exception as e:
    logger.exception(e)