pythonでJSONが繋がっているようなファイルを読み込む方法。

json.loadsは使えない

例えば以下の様なデータが在る場合がある。

{"name": "foo"}
{"name": "bar"}
{"name": "boo"}

通常の方法ではinvalidなJSONなので読み込めない。

import json

s = """
{"name": "foo"}
{"name": "bar"}
{"name": "boo"}
"""
print(json.loads(s))

エラーになる。json.loadsは使えない。

json.decoder.JSONDecodeError: Extra data: line 3 column 1 (char 17)

json.jSONDecoderのraw_decodeを使う

以下の様な関数を定義してあげる。ジェネレーターである必要はあんまりない。

import json
from json.decoder import WHITESPACE


def loads_iter(s):
    size = len(s)
    decoder = json.JSONDecoder()

    end = 0
    while True:
        idx = WHITESPACE.match(s[end:]).end()
        i = end + idx
        if i >= size:
            break
        ob, end = decoder.raw_decode(s, i)
        yield ob

今度は大丈夫。

s = """
{"name": "foo"}
{"name": "bar"}
{"name": "boo"}
"""

print(list(loads_iter(s)))
# [{'name': 'foo'}, {'name': 'bar'}, {'name': 'boo'}]

もちろん以下の様な崩れた一行に収まらない状態でも問題なし。

s = """
{"name": "foo"}
{
"name": "bar"
}
{
"name":
 "boo"
}
"""

print(list(loads_iter(s)))
# [{'name': 'foo'}, {'name': 'bar'}, {'name': 'boo'}]

pythonでサブクラスを定義するときにオプションを渡せるようにしてみる

そういえば、継承時にbase classの他にオプションを取る定義が書けるのわりと最初ビックリするけれどvalidなpythonのコード。

3.6なら__init_subclass__のフックを使うのが楽かもしれない。

たとえば、以下の様なコードを書いてみる。

  • 自身を継承したクラスをchildrenという変数に格納する
  • 継承時にnameというオプションを与えた時にはかわりにその名前を格納する

3.6の場合

3.6以降の場合

class A:
    children = set()

    def __init_subclass__(cls, name=None):
        name = name or cls.__name__
        cls.children.add(name)


class B(A):
    pass


class C(A, name="MaybeA"):
    pass


print(A.children)

# {'B', 'MaybeA'}

3.6以前の場合

メタクラスを使って対応することもできる。ただ自分自身を格納しないようにするのがちょっとトリッキー

class AMeta(type):
    def __new__(self, clsname, bases, attrs, name=None):
        instance = super().__new__(self, clsname, bases, attrs)
        if "children" not in instance.__dict__:
            instance.children.add(name or clsname)
        return instance


class A(metaclass=AMeta):
    children = set()


class B(A):
    pass


class C(A, name="MaybeA"):
    pass


print(A.children)

# {'B', 'MaybeA'}