前言
又是一個忘了寫完的娶靡。牧牢。。姿锭。
marshmallow 是一個 ORM/ODM/框架無關(guān)的庫塔鳍,用于將復(fù)雜的數(shù)據(jù)類型,例如對象與Python原生數(shù)據(jù)類型之間轉(zhuǎn)換的庫呻此。簡單而言轮纫,就是對象序列化和反序列化,實現(xiàn)object -> dict
, object -> list
, string -> dict
, string -> list
的轉(zhuǎn)換焚鲜。(注:這篇文章將以 0.1.0 版本代碼分析掌唾,可能與當(dāng)前官方文檔的例子有些不同)
官網(wǎng)示例
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 版本的源碼結(jié)構(gòu)放前,如下所示
marshmallow
├── __init__.py
├── base.py
├── compat.py
├── core.py # 核心代碼,使用Python元類定義了Serializer糯彬,繼承于BaseSerializer凭语、SerializerMeta
├── exceptions.py
├── fields.py
├── types.py
core.py
先從 core.py 文件開始看起,該文件中主要包括了以下幾個類撩扒,并應(yīng)用了元類編程的思想:
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, {})
可能之前有過元編程經(jīng)驗的人就會發(fā)現(xiàn)這段代碼很熟悉似扔,Serializer 類定義時使用 with_metaclass 方法傳入 SerializerMeta 元類和 BaseSerializer 基類,而 with_metaclass 是一個比較重要的方法搓谆,用來兼容 python2 和 python3 元類使用上的區(qū)別炒辉。
- with_metaclass 函數(shù)中定義了一個內(nèi)部類(metaclass),并使用該內(nèi)部類創(chuàng)建一個臨時類 temporary_class
- 該臨時類是 內(nèi)部類(metaclass) 的實例(元類創(chuàng)建出來的類就是元類的實例), 即是 tempoary_class 類的元類是 metaclass
- 通過上面代碼可以看出臨時類創(chuàng)建時僅僅調(diào)用了
type.__new__
方法
當(dāng)定義 Serializer 類的時候泉手,Serializer 得到了繼承的元類metaclass:
- 實例化 metaclass, 調(diào)用
metaclass.__new__
方法黔寇,即是調(diào)用 meta(name, bases, d), meta 就是 SerializerMeta 元類斩萌,bases 就是 BaseSerializer 基類(要繼承的類) - 調(diào)用 SerializerMeta 元類的
__new__
方法來實例化得到 Serializer
這個地方需要注意一點是:
1缝裤、在定義 Serializer 類的時候,會執(zhí)行 SerializerMeta 元類的__new__ 來創(chuàng)建類术裸,而不是實例化的時候執(zhí)行__new__ 倘是,這是因為在類的定義(創(chuàng)建)過程中,是通過尋找 __metaclass__ 來完成的
2袭艺、上面雖然沒有顯示定義 __metaclass__ ,但由于下面metaclass的規(guī)則搀崭,會將定義的 SerializerMeta 類作為 metaclass 來創(chuàng)建類
3、metaclass 查找的規(guī)則是:如果當(dāng)前類沒有__metaclass__,但有基類猾编,那么就使用第一個基類的__class__作為 __metaclass__,如果沒有 __class__瘤睹,則使用type 來創(chuàng)建類
一個簡單的例子來看看:
# -*- 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 繼承鏈中沒有之前創(chuàng)建的臨時類(tempoary_class)