最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python 序列化和反序列化庫 MarshMallow 的用法實例代碼

 更新時間:2020年02月25日 07:42:19   作者:崔慶才  
marshmallow(Object serialization and deserialization, lightweight and fluffy.)用于對對象進行序列化和反序列化,并同步進行數(shù)據(jù)驗證。這篇文章主要介紹了Python 序列化和反序列化庫 MarshMallow 的用法實例代碼,需要的朋友可以參考下

序列化(Serialization)與反序列化(Deserialization)是RESTful API 開發(fā)中繞不開的一環(huán),開發(fā)時,序列化與反序列化的功能實現(xiàn)中通常也會包含數(shù)據(jù)校驗(Validation)相關(guān)的業(yè)務(wù)邏輯。

Marshmallow 是一個強大的輪子,很好的實現(xiàn)了 object -> dict , objects -> list, string -> dict和 string -> list。

Marshmallow is an ORM/ODM/framework-agnostic library for converting complex datatypes, such as objects, to and from native Python datatypes.

-- From marshmallow官方文檔

Marshmallow的使用,將從下面幾個方面展開,在開始之前,首先需要一個用于序列化和反序列化的類,我直接與marshmallow官方文檔保持一致了:

class User(object):
 def __init__(self, name, email):
  self.name = name
  self.email = email
  self.created_at = dt.datetime.now()

在很多情況下,我們會有把 Python 對象進行序列化或反序列化的需求,比如開發(fā) REST API,比如一些面向?qū)ο蠡臄?shù)據(jù)加載和保存,都會應用到這個功能。

比如這里看一個最基本的例子,這里給到一個 User 的 Class 定義,再給到一個 data 數(shù)據(jù),像這樣:

class User(object):
 def __init__(self, name, age):
 self.name = name
 self.age = age
data = [{
 'name': 'Germey',
 'age': 23
}, {
 'name': 'Mike',
 'age': 20
}]

現(xiàn)在我要把這個 data 快速轉(zhuǎn)成 User 組成的數(shù)組,變成這樣:

[User(name='Germey', age=23), User(name='Mike', age=20)]

你會怎么來實現(xiàn)?

或者我有了上面的列表內(nèi)容,想要轉(zhuǎn)成一個 JSON 字符串,變成這樣:

[{"name": "Germey", "age": 23}, {"name": "Mike", "age": 20}]

你又會怎么操作呢?

另外如果 JSON 數(shù)據(jù)里面有各種各樣的臟數(shù)據(jù),你需要在初始化時驗證這些字段是否合法,另外 User 這個對象里面 name、age 的數(shù)據(jù)類型不同,如何針對不同的數(shù)據(jù)類型進行針對性的類型轉(zhuǎn)換,這個你有更好的實現(xiàn)方案嗎?

初步思路

之前我寫過一篇文章介紹過 attrs 和 cattrs 這兩個庫,它們二者的組合可以非常方便地實現(xiàn)對象的序列化和反序列化。

譬如這樣:

from attr import attrs, attrib
from cattr import structure, unstructure
 
@attrs
class User(object):
 name = attrib()
 age = attrib()
 
data = {
 'name': 'Germey',
 'age': 23
}
user = structure(data, User)
print('user', user)
json = unstructure(user)
print('json', json)

運行結(jié)果:

user User(name='Germey', age=23) json {'name': 'Germey', 'age': 23}

好,這里我們通過 attrs 和 cattrs 這兩個庫來實現(xiàn)了單個對象的轉(zhuǎn)換。

首先我們要肯定一下 attrs 這個庫,它可以極大地簡化 Python 類的定義,同時每個字段可以定義多種數(shù)據(jù)類型。

但 cattrs 這個庫就相對弱一些了,如果把 data 換成數(shù)組,用 cattrs 還是不怎么好轉(zhuǎn)換的,另外它的 structure 和 unstructure 在某些情景下容錯能力較差,所以對于上面的需求,用這兩個庫搭配起來并不是一個最優(yōu)的解決方案。

另外數(shù)據(jù)的校驗也是一個問題,attrs 雖然提供了 validator 的參數(shù),但對于多種類型的數(shù)據(jù)處理的支持并沒有那么強大。

所以,我們想要尋求一個更優(yōu)的解決方案。

更優(yōu)雅的方案

這里推薦一個庫,叫做 marshmallow,它是專門用來支持 Python 對象和原生數(shù)據(jù)相互轉(zhuǎn)換的庫,如實現(xiàn) object -> dict,objects -> list, string -> dict, string -> list 等的轉(zhuǎn)換功能,另外它還提供了非常豐富的數(shù)據(jù)類型轉(zhuǎn)換和校驗 API,幫助我們快速實現(xiàn)數(shù)據(jù)的轉(zhuǎn)換。

要使用 marshmallow 這個庫,需要先安裝下:

pip3 install marshmallow

好了之后,我們在之前的基礎(chǔ)上定義一個 Schema,如下:

class UserSchema(Schema):
 name = fields.Str()
 age = fields.Integer()
 @post_load
 def make(self, data, **kwargs):
 return User(**data)

還是之前的數(shù)據(jù):

data = [{
 'name': 'Germey',
 'age': 23
}, {
 'name': 'Mike',
 'age': 20
}]

這時候我們只需要調(diào)用 Schema 的 load 事件就好了:

schema = UserSchema()
users = schema.load(data, many=True)
print(users)

輸出結(jié)果如下:

[User(name='Germey', age=23), User(name='Mike', age=20)]

這樣,我們非常輕松地完成了 JSON 到 User List 的轉(zhuǎn)換。

有人說,如果是單個數(shù)據(jù)怎么辦呢,只需要把 load 方法的 many 參數(shù)去掉即可:

data = {
 'name': 'Germey',
 'age': 23
}
 
schema = UserSchema()
user = schema.load(data)
print(user)

輸出結(jié)果:

User(name='Germey', age=23)

當然,這僅僅是一個反序列化操作,我們還可以正向進行序列化,以及使用各種各樣的驗證條件。

下面我們再來看看吧。

更方便的序列化

上面的例子我們實現(xiàn)了序列化操作,輸出了 users 為:

[User(name='Germey', age=23), User(name='Mike', age=20)]

有了這個數(shù)據(jù),我們也能輕松實現(xiàn)序列化操作。

序列化操作,使用 dump 方法即可

result = schema.dump(users, many=True)
print('result', result)

運行結(jié)果如下:

result [{'age': 23, 'name': 'Germey'}, {'age': 20, 'name': 'Mike'}]

由于是 List,所以 dump 方法需要加一個參數(shù) many 為 True。

當然對于單個對象,直接使用 dump 同樣是可以的:

result = schema.dump(user)
print('result', result)

運行結(jié)果如下:

result {'name': 'Germey', 'age': 23}

這樣的話,單個、多個對象的序列化也不再是難事。

經(jīng)過上面的操作,我們完成了 object 到 dict 或 list 的轉(zhuǎn)換,即:

object <-> dict objects <-> list

驗證

當然,上面的功能其實并不足以讓你覺得 marshmallow 有多么了不起,其實就是一個對象到基本數(shù)據(jù)的轉(zhuǎn)換嘛。但肯定不止這些,marshmallow 還提供了更加強大啊功能,比如說驗證,Validation。

比如這里我們將 age 這個字段設(shè)置為 hello,它無法被轉(zhuǎn)換成數(shù)值類型,所以肯定會報錯,樣例如下:

data = {
 'name': 'Germey',
 'age': 'hello'
}
from marshmallow import ValidationError
try:
 schema = UserSchema()
 user, errors = schema.load(data)
 print(user, errors)
except ValidationError as e:
 print('e.message', e.messages)
 print('e.valid_data', e.valid_data)

這里如果加載報錯,我們可以直接拿到 Error 的 messages 和 valid_data 對象,它包含了錯誤的信息和正確的字段結(jié)果,運行結(jié)果如下:

e.message {'age': ['Not a valid integer.']} e.valid_data {'name': 'Germey'}

因此,比如我們想要開發(fā)一個功能,比如用戶注冊,表單信息就是提交過來的 data,我們只需要過一遍 Validation,就可以輕松得知哪些數(shù)據(jù)符合要求,哪些不符合要求,接著再進一步進行處理。

當然驗證功能肯定不止這一些,我們再來感受一下另一個示例:

from pprint import pprint
from marshmallow import Schema, fields, validate, ValidationError
class UserSchema(Schema):
 name = fields.Str(validate=validate.Length(min=1))
 permission = fields.Str(validate=validate.OneOf(['read', 'write', 'admin']))
 age = fields.Int(validate=validate.Range(min=18, max=40))
in_data = {'name': '', 'permission': 'invalid', 'age': 71}
try:
 UserSchema().load(in_data)
except ValidationError as err:
 pprint(err.messages)

比如這里的 validate 字段,我們分別校驗了 name、permission、age 三個字段,校驗方式各不相同。

如 name 我們要判斷其最小值為 1,則使用了 Length 對象。permission 必須要是幾個字符串之一,這里又使用了 OneOf 對象,age 又必須是介于某個范圍之間,這里就使用了 Range 對象。

下面我們故意傳入一些錯誤的數(shù)據(jù),看下運行結(jié)果:

{'age': ['Must be greater than or equal to 18 and less than or equal to 40.'], 'name': ['Shorter than minimum length 1.'], 'permission': ['Must be one of: read, write, admin.']}

可以看到,這里也返回了數(shù)據(jù)驗證的結(jié)果,對于不符合條件的字段,一一進行說明。

另外我們也可以自定義驗證方法:

from marshmallow import Schema, fields, ValidationError
def validate_quantity(n):
 if n < 0:
 raise ValidationError('Quantity must be greater than 0.')
 if n > 30:
 raise ValidationError('Quantity must not be greater than 30.')
class ItemSchema(Schema):
 quantity = fields.Integer(validate=validate_quantity)
in_data = {'quantity': 31}
try:
 result = ItemSchema().load(in_data)
except ValidationError as err:
 print(err.messages)

通過自定義方法,同樣可以實現(xiàn)更靈活的驗證,運行結(jié)果:

{'quantity': ['Quantity must not be greater than 30.']}

對于上面的例子,還有更優(yōu)雅的寫法:

from marshmallow import fields, Schema, validates, ValidationError
class ItemSchema(Schema):
 quantity = fields.Integer()
 @validates('quantity')
 def validate_quantity(self, value):
 if value < 0:
  raise ValidationError('Quantity must be greater than 0.')
 if value > 30:
  raise ValidationError('Quantity must not be greater than 30.')

通過定義方法并用 validates 修飾符,使得代碼的書寫更加簡潔。

必填字段

如果要想定義必填字段,只需要在 fields 里面加入 required 參數(shù)并設(shè)置為 True 即可,另外我們還可以自定義錯誤信息,使用 error_messages 即可,例如:

from pprint import pprint
from marshmallow import Schema, fields, ValidationError
class UserSchema(Schema):
 name = fields.String(required=True)
 age = fields.Integer(required=True, error_messages={'required': 'Age is required.'})
 city = fields.String(
 required=True,
 error_messages={'required': {'message': 'City required', 'code': 400}},
 )
 email = fields.Email()
try:
 result = UserSchema().load({'email': 'foo@bar.com'})
except ValidationError as err:
 pprint(err.messages)

默認字段

對于序列化和反序列化字段,marshmallow 還提供了默認值,而且區(qū)分得非常清楚!如 missing 則是在反序列化時自動填充的數(shù)據(jù),default 則是在序列化時自動填充的數(shù)據(jù)。

例如:

from marshmallow import Schema, fields
import datetime as dt
import uuid
class UserSchema(Schema):
 id = fields.UUID(missing=uuid.uuid1)
 birthdate = fields.DateTime(default=dt.datetime(2017, 9, 29))
print(UserSchema().load({}))
print(UserSchema().dump({}))

這里我們都是定義的空數(shù)據(jù),分別進行序列化和反序列化,運行結(jié)果如下:

{'id': UUID('06aa384a-570c-11ea-9869-a0999b0d6843')} {'birthdate': '2017-09-29T00:00:00'}

可以看到,在沒有真實值的情況下,序列化和反序列化都是用了默認值。

這個真的是解決了我之前在 cattrs 序列化和反序列化時候的痛點??!

指定屬性名

在序列化時,Schema 對象會默認使用和自身定義相同的 fields 屬性名,當然也可以自定義,如:

class UserSchema(Schema):
 name = fields.String()
 email_addr = fields.String(attribute='email')
 date_created = fields.DateTime(attribute='created_at')
 
user = User('Keith', email='keith@stones.com')
ser = UserSchema()
result, errors = ser.dump(user)
pprint(result)

運行結(jié)果如下:

{'name': 'Keith', 'email_addr': 'keith@stones.com', 'date_created': '2014-08-17T14:58:57.600623+00:00'}

反序列化也是一樣,例如:

class UserSchema(Schema):
 name = fields.String()
 email = fields.Email(load_from='emailAddress')
data = {
 'name': 'Mike',
 'emailAddress': 'foo@bar.com'
}
s = UserSchema()
result, errors = s.load(data)

運行結(jié)果如下:

{'name': u'Mike', 'email': 'foo@bar.com'}

嵌套屬性

對于嵌套屬性,marshmallow 當然也不在話下,這也是讓我覺得 marshmallow 非常好用的地方,例如:

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)

這樣我們就能充分利用好對象關(guān)聯(lián)外鍵來方便地實現(xiàn)很多關(guān)聯(lián)功能。

以上介紹的內(nèi)容基本算在日常的使用中是夠用了,當然以上都是一些基本的示例,對于更多功能,可以參考 marchmallow 的官方文檔: https://marshmallow.readthedocs.io/en/stable/,強烈推薦大家用起來 。

總結(jié)

到此這篇關(guān)于Python 序列化和反序列化庫 MarshMallow 的用法實例代碼的文章就介紹到這了,更多相關(guān)Python 序列化和反序列化庫 MarshMallow 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何利用python之wxpy模塊玩轉(zhuǎn)微信

    如何利用python之wxpy模塊玩轉(zhuǎn)微信

    這篇文章主要介紹了利用python之wxpy模塊玩轉(zhuǎn)微信,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • 在python中對變量判斷是否為None的三種方法總結(jié)

    在python中對變量判斷是否為None的三種方法總結(jié)

    今天小編就為大家分享一篇在python中對變量判斷是否為None的三種方法總結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • python寫的一個文本編輯器

    python寫的一個文本編輯器

    這篇文章主要介紹了python寫的一個文本編輯器,大家參考使用吧
    2014-01-01
  • python?opencv實現(xiàn)影像拼接

    python?opencv實現(xiàn)影像拼接

    這篇文章主要介紹了python?opencv實現(xiàn)影像拼接,主要包括內(nèi)容又垂直影像拼接vconcat和水平影像拼接hconcat以及縱向拼接多個不同圖片,下面詳細的相關(guān)內(nèi)容,需要的朋友可以參考一下
    2022-03-03
  • 使用Matplotlib創(chuàng)建基本圖表的詳細指南

    使用Matplotlib創(chuàng)建基本圖表的詳細指南

    Matplotlib 是一個功能強大的 Python 庫,用于創(chuàng)建各種類型的圖表和可視化,在本文中,我們將提供一個完整的指南,介紹如何使用 Matplotlib 創(chuàng)建基本的圖表,包括折線圖、散點圖、柱狀圖和餅圖,感興趣的小伙伴跟著小編一起來看看吧
    2024-05-05
  • python?OpenCV計算圖片相似度的5種算法

    python?OpenCV計算圖片相似度的5種算法

    本文主要介紹了python?OpenCV計算圖片相似度的5種算法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • Python辦公自動化處理的10大場景應用示例

    Python辦公自動化處理的10大場景應用示例

    這篇文章主要為大家介紹了Python辦公自動化處理的10大場景應用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • 詳細介紹python類及類的用法

    詳細介紹python類及類的用法

    前面我們介紹了類的創(chuàng)建及面向?qū)ο蟮娜筇匦?本篇將詳細介紹Python 類的成員,成員修飾符,類的特殊成員.需要的朋友可以參考下
    2021-05-05
  • Python QT組件庫qtwidgets的使用

    Python QT組件庫qtwidgets的使用

    這篇文章主要介紹了Python QT組件庫qtwidgets的使用,幫助大家更好的利用python處理圖片,感興趣的朋友可以了解下
    2020-11-11
  • Python實現(xiàn)訪問者模式詳情

    Python實現(xiàn)訪問者模式詳情

    這篇文章主要介紹了Python實現(xiàn)訪問者模式詳情,訪問者模式,指作用于一個對象結(jié)構(gòu)體上的元素的操作。訪問者可以使用戶在不改變該結(jié)構(gòu)體中的類的基礎(chǔ)上定義一個新的操作,下文更多相關(guān)資料,需要的朋友可以參考下
    2022-03-03

最新評論

海安县| 孝昌县| 高雄市| 德阳市| 雅江县| 沅陵县| 郸城县| 山东| 乐都县| 莆田市| 大洼县| 玉龙| 赤水市| 盐池县| 荆门市| 正阳县| 曲沃县| 浪卡子县| 阿坝县| 武陟县| 天津市| 丹巴县| 绥芬河市| 基隆市| 安丘市| 府谷县| 临沧市| 都江堰市| 五华县| 合水县| 泰兴市| 上林县| 棋牌| 七台河市| 梁河县| 车险| 莱芜市| 马龙县| 岳阳市| 军事| 东海县|