JSON変換するクラス

継承して, convertersにそれぞれの属性をJSON化可能なオブジェクトに変換するときに使うcallableなオブジェクトを詰めておく.

```python:seri.py
import json
from unittest import TestCase
import unittest

class JSONSerializable(object):
    """Serialize to json. """

    def to_json(self, exclude=tuple()):
        """
        exclude: List or tuple of attributes that is excluded to serialize.
        """
        data = self.to_serializable_dict(exclude=exclude)
        return json.dumps(data, ensure_ascii=False)

    def to_serializable_dict(self, exclude=tuple()):
        """Convert to dict that is json serializable.
        exclude: List or tuple of attributes that is excluded to serialize.
        """
        data = {}
        for attr, conv in self.converters:
            if attr in exclude:
                continue
            if not hasattr(self, attr):
                continue
            value = getattr(self, attr, None)
            data[attr] = conv(value) if value is not None else None
        return data

class TestJSONSerializable(TestCase):

    def test_1(self):
        """Call to_serializable_dict()."""

        class C(JSONSerializable):
            b = None
            c = 0
            x = 3

            def __init__(self):
                self.y = 4

            @property
            def z(self):
                return 5

            # Convert to prefered type.
            converters = (
                ('a', int),
                ('b', int),
                ('x', int),
                ('y', float),
                ('z', unicode),
                )

        # Try.
        c = C()
        res = c.to_serializable_dict()

        # Verify
        self.assertEqual(set(res.keys()), set(('b', 'x', 'y', 'z')))
        self.assertEqual(res['b'], None)
        self.assertEqual(res['x'], 3)
        self.assertEqual(res['y'], 4.0)
        self.assertEqual(res['z'], u'5')

        return

    def test_2(self):
        """Call to_serializable_dict() with exclude."""

        class C(JSONSerializable):
            x = 3

            def __init__(self):
                self.y = 4

            @property
            def z(self):
                return 5

            # Convert to prefered type.
            converters = (
                ('x', int),
                ('y', float),
                ('z', unicode),
                )

        # Try.
        c = C()
        res = c.to_serializable_dict(exclude=('x','z'))

        # Verify
        self.assertEqual(set(res.keys()), set('y'))
        self.assertEqual(res['y'], 4.0)

        return

    def test_3(self):
        """Call to_json()."""

        from json import loads

        class C(JSONSerializable):
            x = 3

            def __init__(self):
                self.y = 4

            @property
            def z(self):
                return 5

            # Convert to prefered type.
            converters = (
                ('x', int),
                ('y', float),
                ('z', unicode),
                )

        # Try.
        c = C()
        res = c.to_json()

        # Verify
        res_dict = loads(res)
        self.assertEqual(res_dict['x'], 3)
        self.assertEqual(res_dict['y'], 4.0)
        self.assertEqual(res_dict['z'], u'5')

        return

```