marshmallow 庫介紹

前言

又是一個忘了寫完的娶靡。牧牢。。姿锭。

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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市答倡,隨后出現(xiàn)的幾起案子轰传,更是在濱河造成了極大的恐慌,老刑警劉巖瘪撇,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获茬,死亡現(xiàn)場離奇詭異,居然都是意外死亡倔既,警方通過查閱死者的電腦和手機恕曲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來渤涌,“玉大人佩谣,你說我怎么就攤上這事∈蹬睿” “怎么了茸俭?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵吊履,是天一觀的道長。 經(jīng)常有香客問我调鬓,道長艇炎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任腾窝,我火速辦了婚禮冕臭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘燕锥。我一直安慰自己,他們只是感情好悯蝉,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布归形。 她就那樣靜靜地躺著,像睡著了一般鼻由。 火紅的嫁衣襯著肌膚如雪暇榴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天蕉世,我揣著相機與錄音蔼紧,去河邊找鬼。 笑死狠轻,一個胖子當(dāng)著我的面吹牛奸例,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播向楼,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼查吊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了湖蜕?” 一聲冷哼從身側(cè)響起逻卖,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昭抒,沒想到半個月后评也,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡灭返,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年盗迟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆殿。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡诈乒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出婆芦,到底是詐尸還是另有隱情怕磨,我是刑警寧澤喂饥,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站肠鲫,受9級特大地震影響员帮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜导饲,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一捞高、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渣锦,春花似錦硝岗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至听盖,卻和暖如春胀溺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皆看。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工仓坞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人腰吟。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓无埃,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝎困。 傳聞我的和親對象是個殘疾皇子录语,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容