読者です 読者をやめる 読者になる 読者になる

marshmallowのdumpをupdate_fieldsを指定せずに使うと型の調査が入るので遅い。

http://marshmallow.readthedocs.org/en/latest/api_reference.html#marshmallow.Schema.dump

update_fieldsという引数がdefaultでTrueになっていて。これは値のtypeを見て、変換する関数を変えている。具体的なmappingはmarshmallow.schemaにかかれていて以下の様な感じ。

    TYPE_MAPPING = {
        text_type: fields.String,
        binary_type: fields.String,
        dt.datetime: fields.DateTime,
        float: fields.Float,
        bool: fields.Boolean,
        tuple: fields.Raw,
        list: fields.Raw,
        set: fields.Raw,
        int: fields.Integer,
        uuid.UUID: fields.UUID,
        dt.time: fields.Time,
        dt.date: fields.Date,
        dt.timedelta: fields.TimeDelta,
        decimal.Decimal: fields.Decimal,
    }

このため例えば以下のようなコードが動作する。

from marshmallow import Schema, fields
from datetime import datetime


class PersonSchema0(Schema):
    class Meta:
        fields = ("name", "age", "ctime")


class Person(object):
    def __init__(self, name, age, ctime):
        self.name = name
        self.age = age
        self.ctime = ctime


schema = PersonSchema0()
print(schema.dump(Person("foo", 20, datetime.now())))
# MarshalResult(data={'ctime': '2015-03-26T21:34:06.308849+00:00', 'name': 'foo', 'age': 20}, errors={})

PersonSchemaではfieldの型を直接指定していないが、渡された値の型を調べて対応した出力関数でdumpしてくれている。

update_fields=Trueのオーバーヘッド

もちろん先の値の型をチェックしての出力関数の決定にはオーバーヘッドが存在していて。同じ形式の既定の型を出力したい場合にはFalseにすることが速度を気にしたい場合には有効。

from marshmallow import Schema, fields
import time
from datetime import datetime


class PersonSchema0(Schema):
    class Meta:
        fields = ("name", "age", "ctime")


class Person(object):
    def __init__(self, name, age, ctime):
        self.name = name
        self.age = age
        self.ctime = ctime


N = 1000
schema = PersonSchema0()
t = time.time()
person = Person("foo", 20, datetime.now())

for i in range(N):
    schema.dump(person)
print(time.time() - t)

schema = PersonSchema0()
t = time.time()
person = Person("foo", 20, datetime.now())

for i in range(N):
    schema.dump(person, update_fields=False)
print(time.time() - t)

# 0.15188217163085938
# 0.045701026916503906