前言
又是一個忘了寫完的。。。。
marshmallow 是一個 ORM/ODM/框架無關的庫,用于將復雜的數據類型,例如對象與Python原生數據類型之間轉換的庫。簡單而言,就是對象序列化和反序列化,實現object -> dict
, object -> list
, string -> dict
, string -> list
的轉換。(注:這篇文章將以 0.1.0 版本代碼分析,可能與當前官方文檔的例子有些不同)
官網示例
from datetime import date
from marshmallow import Schema, fields, pprint
class ArtistSchema(Schema):
name = fields.Str()
class AlbumSchema(Schema):
title = fields.Str()
release_date = fields.Date()
artist = fields.Nested(ArtistSchema())
bowie = dict(name='David Bowie')
album = dict(artist=bowie, title='Hunky Dory', release_date=date(1971, 12, 17))
schema = AlbumSchema()
result = schema.dump(album)
pprint(result, indent=2)
# { 'artist': {'name': 'David Bowie'},
# 'release_date': '1971-12-17',
# 'title': 'Hunky Dory'}
源碼開篇
先看看 0.1.0 版本的源碼結構,如下所示
marshmallow
├── __init__.py
├── base.py
├── compat.py
├── core.py # 核心代碼,使用Python元類定義了Serializer,繼承于BaseSerializer、SerializerMeta
├── exceptions.py
├── fields.py
├── types.py
core.py
先從 core.py 文件開始看起,該文件中主要包括了以下幾個類,并應用了元類編程的思想:
class SerializerMeta(type):
def __new__(cls, name, bases, attrs):
attrs['_base_fields'] = _get_declared_fields(bases, attrs)
return super(SerializerMeta, cls).__new__(cls, name, bases, attrs)
class BaseSerializer(object):
def __init__(self, data=None):
self._data = data
self.fields = self.__get_fields() # Dict of fields
def __get_fields(self):
""""""
@property
def data(self):
""""""
@property
def json(self):
""""""
class Serializer(with_metaclass(SerializerMeta, BaseSerializer)):
pass
# compat.py
def with_metaclass(meta, *bases):
'''Defines a metaclass.
Creates a dummy class with a dummy metaclass. When subclassed, the dummy
metaclass is used, which has a constructor that instantiates a
new class from the original parent. This ensures that the dummy class and
dummy metaclass are not in the inheritance tree.
Credit to Armin Ronacher.
'''
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})
可能之前有過元編程經驗的人就會發現這段代碼很熟悉,Serializer 類定義時使用 with_metaclass 方法傳入 SerializerMeta 元類和 BaseSerializer 基類,而 with_metaclass 是一個比較重要的方法,用來兼容 python2 和 python3 元類使用上的區別。
- with_metaclass 函數中定義了一個內部類(metaclass),并使用該內部類創建一個臨時類 temporary_class
- 該臨時類是 內部類(metaclass) 的實例(元類創建出來的類就是元類的實例), 即是 tempoary_class 類的元類是 metaclass
- 通過上面代碼可以看出臨時類創建時僅僅調用了
type.__new__
方法
當定義 Serializer 類的時候,Serializer 得到了繼承的元類metaclass:
- 實例化 metaclass, 調用
metaclass.__new__
方法,即是調用 meta(name, bases, d), meta 就是 SerializerMeta 元類,bases 就是 BaseSerializer 基類(要繼承的類) - 調用 SerializerMeta 元類的
__new__
方法來實例化得到 Serializer
這個地方需要注意一點是:
1、在定義 Serializer 類的時候,會執行 SerializerMeta 元類的__new__ 來創建類,而不是實例化的時候執行__new__ ,這是因為在類的定義(創建)過程中,是通過尋找 __metaclass__ 來完成的
2、上面雖然沒有顯示定義 __metaclass__ ,但由于下面metaclass的規則,會將定義的 SerializerMeta 類作為 metaclass 來創建類
3、metaclass 查找的規則是:如果當前類沒有__metaclass__,但有基類,那么就使用第一個基類的__class__作為 __metaclass__,如果沒有 __class__,則使用type 來創建類
一個簡單的例子來看看:
# -*- coding: utf-8 -*-
from datetime import datetime
from marshmallow import Serializer, fields
class Person(object):
def __init__(self, name):
self.name = name
self.date_born = datetime.now()
class PersonSerializer(Serializer):
name = fields.String()
date_born = fields.DateTime()
person = Person(name="guoweikuang")
serialized = PersonSerializer(person)
print(PersonSerializer.__mro__)
# out: (<class '__main__.PersonSerializer'>, <class 'marshmallow.core.Serializer'>, <class 'marshmallow.core.BaseSerializer'>, <type 'object'>)
可以看到 PersonSerializer 繼承鏈中沒有之前創建的臨時類(tempoary_class)