數據類型校驗——schema
背景
一般情況下,我們都是按照既定的數據結構和輸入參數進行在程序開發。但是往往在調試過程中,我們會發現大部分情況下,都是傳入的參數不符合預期。那么針對該問題,我們就需要引入數據類型校驗工具。
如果參數數量較少,限制比較簡單,我們可以使用以下三種方式進行解決:
- 第一種:通過
try...except(或者assert)直接粗暴處理; - 第二種:基于枚舉的思想,通過
if-else處理各種可能;
但上述兩種處理在復雜情況下不具備友好的推廣價值。
那么在Python中有沒有現成的庫可以解決該問題呢?通過查詢,最終發現了Schema。其是一個用于驗證Python數據結構的庫。
接下來將對Schema進行重點介紹。
庫信息
安裝

基本介紹
-
基本數據類型介紹(校驗合格返回對應數據;否則返回
SchemaError)>>> from schema import Schema >>> Schema(int).validate(123) 123 >>> Schema(int).validate('123') Traceback (most recent call last): ... schema.SchemaUnexpectedTypeError: '123' should be instance of 'int' >>> Schema(object).validate('hai') 'hai' -
Callables(可調用對象):
Scema(func),其中func()-->Boole,此時如果為真(True),則返回被校驗對象;否則返回SchemaError
>>> import os
>>> Schema(os.path.exists).validate('./')
'./'
>>> Schema(os.path.exists).validate('./non-existent/')
Traceback (most recent call last):
...
schema.SchemaError: exists('./non-existent/') should evaluate to True
-
Validatables(可驗證)
- 正則表達式
>>> from schema import Regex >>> import re >>> Regex(r'^foo').validate('foobar') 'foobar' >>> Regex(r'^[A-Z]+$', flags=re.I).validate('those-dashes-dont-match') Traceback (most recent call last): ... schema.SchemaError: Regex('^[A-Z]+$', flags=re.IGNORECASE) does not match 'those-dashes-dont-match'-
加工后的數據,
func可以是Use(int):表示將原始數據轉換成int后進行校驗;如果想保持原始不被修改,可以使用
Const; -
也可以使用
lambda匿名函數,示例:
>> from schema import Use, Const, And, Schema >> from datetime import datetime >> is_future = lambda date: datetime.now() > date >> to_json = lambda v: {"timestamp": v} >> Schema(And(Const(And(Use(datetime.fromtimestamp), is_future)), Use(to_json))).validate(1234567890) {"timestamp": 1234567890} -
LIsts,similar containers(列表,類似容器)
如果
func是list、tuple、set對象,它將驗證相應數據容器的內容 針對該容器中列出的所有模式,并聚合所有錯誤。>>> Schema([1, 0]).validate([1, 1, 0, 1]) [1, 1, 0, 1] >>> Schema((int, float)).validate((5, 7, 8, 'not int or float here')) Traceback (most recent call last): ... schema.SchemaError: Or(<class 'int'>, <class 'float'>) did not validate 'not int or float here' 'not int or float here' should be instance of 'int' 'not int or float here' should be instance of 'float' -
字典
- 對鍵和值的值的校驗
>>> d = Schema({'name': str, ... 'age': lambda n: 18 <= n <= 99}).validate({'name': 'Sue', 'age': 28}) >>> assert d == {'name': 'Sue', 'age': 28}- 對字典所有對象都進行校驗,即鍵、值以及它們的值;
```python >>> schema = Schema({str: int, # string keys should have integer values ... int: None}) # int keys should be always None >>> data = schema.validate({'key1': 1, 'key2': 2, ... 10: None, 20: None}) >>> schema.validate({'key1': 1, ... 10: 'not None here'}) Traceback (most recent call last): ... schema.SchemaError: Key '10' error: None does not match 'not None here' ``` -
選擇性參數校驗
>>> from schema import Optional >>> Schema({Optional('color', default='blue'): str, ... str: str}).validate({'texture': 'furry'} ... ) == {'color': 'blue', 'texture': 'furry'} True -
And,Or
>>> from schema import And, Or
>>> Schema({'age': And(int, lambda n: 0 < n < 99)}).validate({'age': 7})
{'age': 7}
>>> Schema({'password': And(str, lambda s: len(s) > 6)}).validate({'password': 'hai'})
Traceback (most recent call last):
...
schema.SchemaError: Key 'password' error:
<lambda>('hai') should evaluate to True
>>> Schema(And(Or(int, float), lambda x: x > 0)).validate(3.1415)
3.1415
-
輸入數據中多余參數的處理機制
如本來
func是用來校驗a,b,c三個參數的輸入,那么用戶在輸入的數據中包含a,b,c,d多了一個d參數,此時我們如何進行處理?Schema提供了ignore_extra_keys用于處理該問題。#False:會觸發schema.SchemaWrongKeyError >>> schema = Schema({'name': str}, ignore_extra_keys=True) >>> schema.validate({'name': 'Sam', 'age': '42'}) #age被過濾掉 {'name': 'Sam'} -
自定義驗證
class EventSchema(schema.Schema):
def validate(self, data, _is_event_schema=True):
data = super(EventSchema, self).validate(data, _is_event_schema=False)
if _is_event_schema and data.get("minimum", None) is None:
data["minimum"] = data["capacity"]
return data
events_schema = schema.Schema(
{
str: EventSchema({
"capacity": int,
schema.Optional("minimum"): int, # default to capacity
})
}
)
data = {'event1': {'capacity': 1}, 'event2': {'capacity': 2, 'minimum': 3}}
events = events_schema.validate(data)
assert events['event1']['minimum'] == 1 # == capacity
assert events['event2']['minimum'] == 3
-
報錯信息處理
such as
Schema,And,Or,Regex,Use可以傳遞error關鍵字參數,輸出對應的報錯信息。>>> Schema(Use(int, error='Invalid year')).validate('XVII') Traceback (most recent call last): ... schema.SchemaError: Invalid year
示例
示例1
JSON字符串的多層校驗:
- 第一步使用:
json.loads將其轉換成{}; - 然后對鍵值進行值類型校驗,其中存在可選性參數(
Optional)和嵌套型參數(files對象)
>>> gist = '''{"description": "the description for this gist",
... "public": true,
... "files": {
... "file1.txt": {"content": "String file contents"},
... "other.txt": {"content": "Another file contents"}}}'''
>>> from schema import Schema, And, Use, Optional
>>> import json
>>> gist_schema = Schema(And(Use(json.loads), # first convert from JSON
... # use str since json returns unicode
... {Optional('description'): str,
... 'public': bool,
... 'files': {str: {'content': str}}}))
>>> gist = gist_schema.validate(gist)
# gist:
{u'description': u'the description for this gist',
u'files': {u'file1.txt': {u'content': u'String file contents'},
u'other.txt': {u'content': u'Another file contents'}},
u'public': True}
這是一個信號分析場景,算法要求如下:
- 窗函數只支持:hann,hamming,boxcar,triang,gaussian五種;
- 輸入的數據類型:支持:dB和Pvar;
- 測點名稱:批量輸入(list),且每個都是字符型;
- 采樣率與測點保持一致,但數據本身是float;
- 常量值E,范圍(0,100),不包含邊界
- 譜分析類型有兩種;
應用場景:
- 第一種情況:需要除譜分析以外的所有參數;
- 第二種情況:所有參數
目標:
? 定義一個數據校驗器,用來處理上述應用場景涉及到的所有參數。
from schema import And, Const, Schema, Use, Optional
# 定義傳參數據類型以及基本格式要求
VALIDATE_FORMAT = Schema({
"window_name" : And(str,
lambda x: x in "hann hamming boxcar triang gaussian".split(),
error=""
),
"mode" : And(str,
lambda x: x in "dB Pvar".split(),
error=""),
"stations" : And(list,
lambda x: isinstance(x[0], str),
error=""),
"sample_rates" : And(list,
lambda x: isinstance(float(x[0]), float),
error=""
),
"E" : And(Use(float),
lambda x: 0 < x < 100,
error=""),
Optional("spectral_type"): And(str,
lambda x: x in "PK RMS".split(),
error="")
}, ignore_extra_keys=True)

浙公網安備 33010602011771號