memo

Python

制御構造

if

while + else

while ループを抜けると else が実行される。
(break で抜けた場合は else は実行されない。)

idx = 1
sum = 0

while idx <= 10:
  if idx == 11:
    break
  sum += idx
  idx += 1
else:
  print(sum)
# => 55

for

sum = 0
for ii in range(10):
  sum += ii
else:
  print(sum)
# => 45

range(10)range(0, 10, 1) と同じ
0 から 1 ずつ増えて 9(10未満)で終わり。
(for も break で抜けた場合は else は実行されない。)

例外処理

try:
    ii = int('123')
    print(ii)
    list = []
    print(list[0])
except ValueError as ex:
    print(ex)
except Exception as ex:
    print(ex)
else:
    print('no error')
finally:
    print('finally')

文字列

長い文字列

文字列のスライス(substring)

日付

書式

文字列から datetime に変換

文字列が日付として正しいかチェック

# 不正な日付を datetime に変換しようとすると「ValueError: unconverted data remains: 2」エラーになる。
date = datetime.datetime.strptime('20240132', '%Y%m%d')

=> 「remains: 2」は、最後の 2が変換できなかった、という意味。

計算

データ構造

リスト

list = [1,2,3,4,5]

タプル

tuple = (1,2,3,4,5)

ディクショナリ

dic = { 'id': 1, 'name': 'hoge' }
# 別の書き方
dic2 = dict( id=1, name='hoge' )
dic3 = dict([('id', 1), ('name', 'hoge')])

セット

s = { 1, 2, 3, 2, 4, 5}
print(set)  # {1, 2, 3, 4, 5} => 重複した 2 が 1つにまとめられる

関数

パラメーター

キーワード引数、デフォルト引数

def func(hoge, fuga, foo=3):
  print("hoge=", hoge)
  print("fuga=", fuga)
  print("foo=", foo)

# キーワード引数で呼び出す
func(fuga="fuga!", hoge="hoge!", foo=1)
# 1番目は位置引数で、2つ目からはキーワード引数で呼び出す
func("hoge#", foo=1, fuga="fuga#")
# 1, 2番目は一引数で、3番目はデフォルト引数で呼び出す
func("hoge$", "fuga$")

デフォルト引数に空のリストをセットする場合、リストが再利用されることに注意する。

def func(num, hoge=[]):
  hoge.append(num)  # 2回目以降に呼び出す時は、前回呼び出された時のリストに対して追加される。
  return hoge

list = func(1)
print(list)  # [1]
list = func(2)
print(list)  # [1, 2]

これを避けるには、デフォルト引数に None を指定し、関数内で None の場合にリストを初期化する。

def func(num, hoge=None):
  if hoge is None:  # 何回呼び出されても、毎回引数が省略された場合はリストを初期化する。
    hoge = []
  hoge.append(num)
  return hoge

list = func(1)
print(list)  # [1]
list = func(2)
print(list)  # [2] <= 2だけになる
キーワード引数をディクショナリとして渡す
def func(**args):
  print(args)
  for k, v in args.items():
    print(k, '=', v)

func(state='Hawaii', island='Oafu', city='Honolulu')

引数をタプルとして渡す

パラメーター名の前に * を付けるとタプルとして受け取る。

def func(*args):
  print(args)
  state, island, city = args
  print('state=', state, ', island=', island, ', city=', city)

func('Hawaii', 'Oafu', 'Honolulu')
位置引数とタプルを混在して渡す
def func(state, *args):
  print('state=', state)
  for arg in args:
    print(arg)

func('Hawaii', 'Oafu', 'Honolulu')

位置引数, タプル, ディクショナリの引数を混在して渡す

def func(country, *states, **args):
  print('country=', country)
  print('states=', states)
  for k, v in args.items():
    print(k, '=', v)

# USA は位置パラメーター, California, New York, Florida はタプル, 残りはディクショナリとして渡す。
func('USA', 'California', 'New York', 'Florida', state='Hawaii', island='Oafu', city='Honolulu')

デコレーター

パラメーターで渡された関数を実行する前後に処理を追加し、そのデコレーターを関数と関連付けて実行する。

def debug_message(func):
  def wrapper(*args, **kwargs):
    print('args:', args)
    result = func(*args, **kwargs)
    print('result:', result)
    return result
  return wrapper

def trace_message(func):
  def wrapper(*args, **kwargs):
    print('start:', func.__name__)
    result = func(*args, **kwargs)
    print('end:', func.__name__)
    return result
  return wrapper

@trace_message
@debug_message
def traced_func(country, *states, **args):
  print('country=', country)
  print('states=', states)
  for k, v in args.items():
    print(k, '=', v)
  return 'OK'

# USA は位置パラメーター, California, New York, Florida はタプル, 残りはディクショナリとして渡す。
traced_func('USA', 'California', 'New York', 'Florida', state='Hawaii', island='Oafu', city='Honolulu')

クラス

with

プロパティ

抽象クラス

import abc

class MetaClass(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def hello(self):
        pass

class Hoge(MetaClass):
    def __init__(self):
        print('init')

meta = MetaClass()  # <= TypeError: Can't instantiate abstract class MetaClass with abstract methods hello
hoge = Hoge()       # <= TypeError: Can't instantiate abstract class Hoge with abstract methods hello

@abc.abstractmethod が付与されたメソッドを継承先で実装していないと例外がスローされる。

クラス変数、クラスメソッド、スタティックメソッド

class Hoge():
    class_value = 'hoge'
    __class_value = 'private hoge'

    @classmethod
    def class_hello(cls):
        print(cls.class_value)    # クラス変数を参照する場合はパラメーターの cls を付ける

    @staticmethod
    def static_hello():
        print(Hoge.class_value)    # クラス変数を参照する場合はクラス名を付ける
        print(Hoge.__class_value)  # プライベータなクラス変数をクラス内から参照

Hoge.class_hello()         # hoge
Hoge.static_hello()        # hoge
print(Hoge.class_value)    # hoge <= 直接クラス変数を参照することも可能
print(Hoge.__class_value)  # private なクラス変数を外から参照すると AttributeError: type object 'Hoge' has no attribute '__class_value'

特殊メソッド

ファイル

その他

コマンドライン引数

import sys

print(sys.argv[0])  # 自身のスクリプト名
print(sys.argv[1])  # 最初の引数

I/O

Tips

スクリプトが直接起動された場合だけ、main を実行する。

def main():
   # メイン処理

if __name__ == '__main__':
    main()

import パスを表示

python3 -c "import sys; print(sys.path)"

簡易 HTTP サーバーをたてる

python -m http.server 8000

UTF-8 から SJIS 変換して、変換不能文字を特定の文字で置き換える。

サンプル by Gemini

import codecs

def convert_and_replace(input_file, output_file, replace_char):
    with open(input_file, 'r', encoding='utf-8') as f_in:
        data = f_in.read()

    try:
        # SJISに変換
        converted_data = data.encode('shift-jis')
    except UnicodeEncodeError as e:
        # 変換できない文字があった場合
        print(f"変換エラー: {e}")

        # 代替文字に変換
        converted_data = data.encode('shift-jis', errors='replace', replacement=replace_char)

    with open(output_file, 'w', encoding='shift-jis') as f_out:
        f_out.write(converted_data.decode('shift-jis'))

if __name__ == '__main__':
    input_file = 'input.txt'
    output_file = 'output.txt'
    replace_char = '?'  # SJISにない文字を置き換える文字

    convert_and_replace(input_file, output_file, replace_char)

または

import codecs

def convert_and_replace_with_codecs(input_file, output_file, replace_char):
    with open(input_file, 'r', encoding='utf-8') as f_in:
        data = f_in.read()

    try:
        # SJISに変換
        encoder = codecs.getencoder('shift-jis')
        converted_data, _ = encoder(data, errors='replace', replacement=replace_char)
    except UnicodeEncodeError as e:
        print(f"変換エラー: {e}")

    with open(output_file, 'w', encoding='shift-jis') as f_out:
        f_out.write(converted_data)

if __name__ == '__main__':
    input_file = 'input.txt'
    output_file = 'output.txt'
    replace_char = '?'  # SJISにない文字を置き換える文字

    convert_and_replace_with_codecs(input_file, output_file, replace_char)