国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python 參數(shù)校驗的進(jìn)化

xfee / 2104人閱讀

摘要:事情的起因是感覺目前項目中的參數(shù)校驗方法寫的太簡單了很多時候需要在層再處理于是就動手準(zhǔn)備寫一個好用一點的可以自定義校驗參數(shù)規(guī)則的參數(shù)校驗器考慮到要可以靈活的配置就萌生了大概的印象使用參數(shù)參數(shù)等等對參數(shù)進(jìn)行規(guī)則綁定使用裝飾器可擴(kuò)展可以自定

事情的起因是感覺目前項目中的參數(shù)校驗方法寫的太簡單了,很多時候需要在server層再if else處理,于是就動手準(zhǔn)備寫一個好用一點的,可以自定義校驗參數(shù)規(guī)則的參數(shù)校驗器,考慮到要可以靈活的配置就萌生了大概的印象:

使用map - 參數(shù)A:ruleA,參數(shù)B-ruleB..等等,對參數(shù)進(jìn)行規(guī)則綁定

使用裝飾器

可擴(kuò)展,可以自定義校驗規(guī)則

于是第一個版本實現(xiàn)如下:

版本1
# -*- coding:utf-8 -*-
__author__ = "aleimu"
__date__ = "2018-12-6"
__doc__ = "一個實用的入?yún)⑿r炑b飾器--針對目前,前端 url?&a=1&b=2或-d"a=1&b=2c=qwe"形式的非json(所有參數(shù)都是str類型)" 
          "入?yún)⒌男r?

import copy
import traceback
from collections import OrderedDict
from functools import wraps
from flask import Flask, json, jsonify, request

app = Flask(__name__)


def verify_args(need=None, length=None, check=None, strip=True, default=(False, None), diy_func=None, release=False):
    """
    約束:
    1. 簡化了傳參校驗,使用位置傳參或者關(guān)鍵詞傳參(一個參數(shù)對應(yīng)一個參數(shù)),不允許使用one to list等python高級傳參特性
    2. 所有的參數(shù)都是str/unicode類型的,前端沒有使用json帶參數(shù)類型的入?yún)⒎绞?    :param need: 必須參數(shù),且不能為None或者""
    :param length: 參數(shù)長度范圍
    :param check:  str的常用類方法/屬性如下:
        isalnum 判斷字符串中只能由字母和數(shù)字的組合,不能有特殊符號
        isalpha 字符串里面都是字母,并且至少是一個字母,結(jié)果就為真,(漢字也可以)其他情況為假
        isdigit 函數(shù)判斷是否全為數(shù)字
    :param strip:對字段進(jìn)行前后過濾空格
    :param default:將"" 裝換成None
    :param diy_func:自定義的對某一參數(shù)的校驗函數(shù)格式: {key:func},類似check, diy_func={"a": lambda x: x + "aa"})
    :param release:發(fā)生參數(shù)校驗異常后是否依然讓參數(shù)進(jìn)入主流程函數(shù)
    :return:
    """

    def wraps_1(f):
        @wraps(f)
        def wraps_2(*args, **kwargs):
            if release:
                args_bak = args[:]
                kwargs_bak = copy.deepcopy(kwargs)  # 下面流程異常時,是否直接使用 原參數(shù)傳入f todo
            print ("in", args, kwargs)
            args_template = f.func_code.co_varnames
            print("args_template:", args_template)
            args_dict = OrderedDict()
            req_args_need_list = []
            req_args_types_list = []
            try:
                for i, x in enumerate(args):
                    args_dict[args_template[i]] = x
                sorted_kwargs = sort_by_co_varnames(args_template, kwargs)
                args_dict.update(sorted_kwargs)
                print("args_dict:", args_dict)
                # need
                if need:
                    for k in need:
                        if k not in args_dict:
                            req_args_need_list.append(k)
                        else:
                            if args_dict[k] == None or args_dict[k] == "":
                                req_args_need_list.append(k)
                    if req_args_need_list:
                        return False, "%s is in need" % req_args_need_list
                # strip
                if strip:
                    for k in args_dict:
                        if args_dict[k]:
                            args_dict[k] = args_dict[k].strip()
                # length
                if length:
                    for k in args_dict:
                        if k in length:
                            if not (len(args_dict[k]) >= length[k][0] and len(args_dict[k]) <= length[k][1]):
                                return False, "%s length err" % k
                # default:
                if default[0]:
                    for x in args_dict:
                        if args_dict[x] == "":
                            args_dict[x] = default[1]
                # check
                if check:
                    for k in check:
                        check_func = getattr(type(args_dict[k]), check[k], None)
                        if not (k in args_dict and check_func and check_func(args_dict[k])):
                            req_args_types_list.append(k)
                    if req_args_types_list:
                        return False, "%s type err" % req_args_types_list
                # diy_func
                if diy_func:
                    for k in args_dict:
                        if k in diy_func:
                            args_dict[k] = diy_func[k](args_dict[k])
            except Exception as e:
                print("verify_args catch err: ", traceback.format_exc())
                if release:
                    return f(*args_bak, **kwargs_bak)
                else:
                    return False, str(e)
            return f(*args_dict.values())

        return wraps_2

    return wraps_1


def sort_by_co_varnames(all_args, kwargs):
    new_ordered = OrderedDict()
    for x in all_args:
        if x in kwargs:
            new_ordered[x] = kwargs[x]
    return new_ordered


@app.route("/", methods=["GET", "POST", "PUT"])
def index():
    a = request.values.get("a")
    b = request.values.get("b")
    c = request.values.get("c")
    d = request.values.get("d")
    e = request.values.get("e")
    f = request.values.get("f")
    g = request.values.get("g")
    status, data = todo(a, b, c, d, e=e, f=f, g=g)
    if status:
        return jsonify({"code": 200, "data": data, "err": None})
    else:
        return jsonify({"code": 500, "data": None, "err": data})


@verify_args(need=["a", "b", "c"], length={"a": (6, 50)}, strip=True,
             check={"b": "isdigit", "c": "isalnum"},
             default=(True, None),
             diy_func={"a": lambda x: x + "aa"})
def todo(a, b, c, d, e="  1  ", f="2    ", g=""):
    return True, {"a": a, "b": b, "c": c, "d": d, "e": e, "f": f, "g": g}


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=6000, debug=True)

"""
# curl "http://127.0.0.1:6000/" -d "pwd=123&a=1111111&b=2&c=3&d=d&e=eeeeee&f=12345&g="
{
  "code": 200,
  "data": {
    "a": "1111111aa",
    "b": "2",
    "c": "3",
    "d": "d",
    "e": "eeeeee",
    "f": "12345",
    "g": null
  },
  "err": null
}

# curl "http://127.0.0.1:6000/" -d "pwd=123&a=1111111&b=2&c=3346()*&d=d&e=eeeeee&f=12345&g="
{
  "code": 500,
  "data": null,
  "err": "["c"] type err"
}

# curl "http://127.0.0.1:6000/" -d "pwd=123&a=1111111&b=2&c=&d=d&e=eeeeee&f=12345&g="    
{                                                                                        
  "code": 500,                                                                           
  "data": null,                                                                          
  "err": "["c"] is in need"                                                              
}   

# curl "http://127.0.0.1:6000/" -d "pwd=123&a=1111111&b=2&c=  1  &d=d&e=eeeeee&f=12345&g="  
{                                                                                           
  "code": 200,                                                                              
  "data": {                                                                                 
    "a": "1111111aa",                                                                       
    "b": "2",                                                                               
    "c": "1",                                                                               
    "d": "d",                                                                               
    "e": "eeeeee",                                                                          
    "f": "12345",                                                                           
    "g": null                                                                               
  },                                                                                        
  "err": null                                                                               
}                                                                                                                                                                                
"""

第一個版本切合了當(dāng)前項目中經(jīng)常遇到的校驗問題,實現(xiàn)起來較簡單,基本滿足要求.
想要更通用點,更多校驗規(guī)則一些,就需要每次為verify_args添加參數(shù)寫if else了,嗯.....有點不優(yōu)雅啊,于是去看github上有啥好的實現(xiàn).
找到了如下幾個項目:

https://github.com/keleshev/s... 嗯,1.6K的star,思路一致,實現(xiàn)的優(yōu)雅,但是不好擴(kuò)展啊....

https://github.com/kvesteri/v... 額,Python Data Validation for Humans?. not for me....

https://github.com/mansam/val... 嗯,思路一致,實現(xiàn)也簡單,挺好擴(kuò)展的,就用它了!

這里說說validator.py ,給個例子

from validator import Required, Not, Truthy, Blank, Range, Equals, In, validate

# let"s say that my dictionary needs to meet the following rules...
rules = {
    "foo": [Required, Equals(123)],
    "bar": [Required, Truthy()],
    "baz": [In(["spam", "eggs", "bacon"])],
    "qux": [Not(Range(1, 100))] # by default, Range is inclusive
}

# then this following dict would pass:
passes = {
    "foo": 123,
    "bar": True, # or a non-empty string, or a non-zero int, etc...
    "baz": "spam",
    "qux": 101
}
print validate(rules, passes)
# (True, {})

# but this one would fail
fails = {
    "foo": 321,
    "bar": False, # or 0, or [], or an empty string, etc...
    "baz": "barf",
    "qux": 99
}
print validate(rules, fails)
# (False,
#  {
#  "foo": ["must be equal to "123""],
#  "bar": ["must be True-equivalent value"],
#  "baz": ["must be one of ["spam", "eggs", "bacon"]"],
#  "qux": ["must not fall between 1 and 100"]
#  })

嗯,使用第一個版本封裝一下validator.py就好了!考慮到需要寫個dome來試試,就選了flask,嗯,對了,先去github 上搜一下 flask validator 沒準(zhǔn)已經(jīng)有現(xiàn)成的呢,實現(xiàn)思路基本一致,但是......前幾個star多的都不令人滿意,還是自己造輪子吧.
先實現(xiàn)常見的在route上加裝飾器版本,這樣的話,就可以直接接收request收到的參數(shù),然后直接校驗了,有問題就直接返回錯誤給調(diào)用者,于是有了版本2

版本2
rules_example = {
    "a": [Required, Equals("123")],  # foo must be exactly equal to 123
    "b": [Required, Truthy()],  # bar must be equivalent to True
    "c": [In(["spam", "eggs", "bacon"])],  # baz must be one of these options
    "d": [Not(Range(1, 100))],  # qux must not be a number between 1 and 100 inclusive
    "e": [Length(0, maximum=5)],
    "f": [Required, InstanceOf(str)],
    "g": [Required, Not(In(["spam", "eggs", "bacon"]))],
    "h": [Required, Pattern("dd\%")],
    "i": [Required, GreaterThan(1, reverse=True, auto=True)],  # auto 自動轉(zhuǎn)換成float類型來做比較
    "j": [lambda x: x == "bar"],
    "k": [Required, Isalnum()],  # 判斷字符串中只能由字母和數(shù)字的組合,不能有特殊符號
    "l": [Required, Isalpha()],  # 字符串里面都是字母,并且至少是一個字母,結(jié)果就為真,(漢字也可以)其他情況為假
    "m": [Required, Isdigit()],  # 判斷字符串是否全為數(shù)字
}


def validator_wrap(rules, strip=True, diy_func=None):
    """裝飾器版 - 只能檢測是否符合規(guī)則,不能修改參數(shù)
    :param rules:參數(shù)的校驗規(guī)則,map
    :param strip:對字段進(jìn)行前后空格檢測
    :param diy_func:自定義的對某一參數(shù)的校驗函數(shù)格式: {key:func},類似check, diy_func={"a": lambda x: x=="aa"})
    """

    def decorator(f):
        @wraps(f)
        def decorated_func(*args, **kwargs):
            try:
                args_dict = OrderedDict()
                if request.values:
                    args_dict.update(request.values)
                if request.json:
                    args_dict.update(request.json)
                # strip
                if strip:
                    for k in args_dict:
                        if args_dict[k] and isstr(args_dict[k]):
                            if args_dict[k][0] == " " or args_dict[k][-1] == " ":
                                return jsonify({"code": 500, "data": None, "err": "%s should not contain spaces" % k})
                # diy_func
                if diy_func:
                    for k in args_dict:
                        if k in diy_func:
                            args_dict[k] = diy_func[k](args_dict[k])
                # rules
                if rules:
                    result, err = validate(rules, args_dict)
                    if not result:
                        return jsonify(
                            {"code": 500, "data": None, "err": err})
            except Exception as e:
                print("verify_args catch err: ", traceback.format_exc())
                return jsonify({"code": 500, "data": None, "err": str(e)})
            return f(*args, **kwargs)

        return decorated_func

    return decorator
    
@app.route("/wrap", methods=["GET", "POST", "PUT"])
@validator_wrap(rules=rules_example, strip=True)  # 姿勢 1:只能檢測是否符合規(guī)則,不能修改參數(shù),不符合就會直接返回json給調(diào)用者
def wrap_example():
    a = request.values.get("a")
    b = request.values.get("b")
    c = request.values.get("c")
    d = request.values.get("d")
    e = request.values.get("e")
    f = request.values.get("f")
    g = request.values.get("g")
    h = request.values.get("h")
    i = request.values.get("i")
    j = request.values.get("j")
    k = request.values.get("k")
    l = request.values.get("l")
    m = request.values.get("m")
    status, data = todo(a=a, b=b, c=c, d=d, e=e, f=f, g=g, h=h, i=i, j=j, k=k, l=l, m=m)
    if status:
        return jsonify({"code": 200, "data": data, "err": None})
    else:
        return jsonify({"code": 500, "data": None, "err": data})

好像挺好的,基本滿足要求了,但是再route上加裝飾器,那就改變不了參數(shù)的值了,雖然有些參數(shù)不一定符合要求,但是簡單修補(bǔ)一下還是可以用的,還得繼續(xù)尋找能夠改變?nèi)雲(yún)⒌姆绞?第一反應(yīng)是在裝飾器中修改request.values或者request.json的值,讓進(jìn)入到主函數(shù)后獲取更新后的值,上下求索未得門徑,request.value.update方法是被禁用的,繼續(xù)看源碼,后面的實現(xiàn)使用了dict的復(fù)雜封裝,不好改啊,這樣太繞了,還是直接調(diào)用函數(shù)吧,不玩裝飾器了.于是又了版本3

版本3
def validator_func(rules, strip=True, default=(False, None), diy_func=None, release=False):
    """函數(shù)版-返回dict,代替request.values/request.json
    :param rules:參數(shù)的校驗規(guī)則,map
    :param strip:對字段進(jìn)行前后過濾空格
    :param default:將"" 裝換成None
    :param diy_func:自定義的對某一參數(shù)的校驗函數(shù)格式: {key:func},類似check, diy_func={"a": lambda x: x + "aa"})
    :param release:發(fā)生參數(shù)校驗異常后是否依然讓參數(shù)進(jìn)入主流程函數(shù)
    """
    args_dict = OrderedDict()
    try:
        if request.values:
            args_dict.update(request.values)
        if request.json:
            args_dict.update(request.json)
        if release:
            args_dict_copy = copy.deepcopy(args_dict)  # 下面流程異常時,是否直接使用 原參數(shù)傳入f # fixme
        # strip
        if strip:
            for k in args_dict:
                if isstr(args_dict[k]):
                    args_dict[k] = args_dict[k].strip()
        # default
        if default[0]:
            for x in args_dict:
                if args_dict[x] == "":
                    args_dict[x] = default[1]
        # diy_func
        if diy_func:
            for k in args_dict:
                if k in diy_func:
                    args_dict[k] = diy_func[k](args_dict[k])
        # rules
        if rules:
            result, err = validate(rules, args_dict)
            if not result:
                return False, err
    except Exception as e:
        print("verify_args catch err: ", traceback.format_exc())  # TODO
        if release:
            return True, args_dict_copy
        else:
            return False, str(e)
    return True, args_dict

@app.route("/func", methods=["GET", "POST", "PUT"])
def func_example():
    result, request_args = validator_func(rules=rules_example, strip=True)  # 姿勢 2
    if not result:
        return jsonify({"code": 500, "data": None, "err": request_args})
    a = request_args.get("a")
    b = request_args.get("b")
    c = request_args.get("c")
    d = request_args.get("d")
    e = request_args.get("e")
    f = request_args.get("f")
    g = request_args.get("g")
    h = request_args.get("h")
    i = request_args.get("i")
    j = request_args.get("j")
    k = request_args.get("k")
    l = request_args.get("l")
    m = request_args.get("m")
    status, data = todo(a=a, b=b, c=c, d=d, e=e, f=f, g=g, h=h, i=i, j=j, k=k, l=l, m=m)
    if status:
        return jsonify({"code": 200, "data": data, "err": None})
    else:
        return jsonify({"code": 500, "data": None, "err": data})

嗯,還行吧,就是不怎么優(yōu)雅,還是有點喜歡裝飾器版本,但是苦于能力有限,不想看ImmutableMultiDict,MultiDict的實現(xiàn),還是將第一個版本融合一下吧,裝飾route不行,裝飾todo還不行嗎.于是有了版本4

版本4
def validator_args(rules, strip=True, default=(False, None), diy_func=None, release=False):
    """針對普通函數(shù)的參數(shù)校驗的裝飾器
    :param rules:參數(shù)的校驗規(guī)則,map
    :param strip:對字段進(jìn)行前后過濾空格
    :param default:將"" 裝換成None
    :param diy_func:自定義的對某一參數(shù)的校驗函數(shù)格式: {key:func},類似check, diy_func={"a": lambda x: x + "aa"})
    :param release:發(fā)生參數(shù)校驗異常后是否依然讓參數(shù)進(jìn)入主流程函數(shù)
    """

    def decorator(f):
        @wraps(f)
        def decorated_func(*args, **kwargs):
            if release:
                args_bak = args[:]
                kwargs_bak = copy.deepcopy(kwargs)  # 下面流程異常時,是否直接使用 原參數(shù)傳入f # fixme
            try:
                args_template = f.func_code.co_varnames
            except:
                args_template = f.__code__.co_varnames
            args_dict = OrderedDict()
            try:
                for i, x in enumerate(args):
                    args_dict[args_template[i]] = x
                sorted_kwargs = sort_by_co_varnames(args_template, kwargs)
                args_dict.update(sorted_kwargs)
                # strip
                if strip:
                    for k in args_dict:
                        if isstr(args_dict[k]):
                            args_dict[k] = args_dict[k].strip()
                # default
                if default[0]:
                    for x in args_dict:
                        if args_dict[x] == "":
                            args_dict[x] = default[1]
                # diy_func
                if diy_func:
                    for k in args_dict:
                        if k in diy_func:
                            args_dict[k] = diy_func[k](args_dict[k])
                # rules
                if rules:
                    result, err = validate(rules, args_dict)
                    if not result:
                        return False, err
            except Exception as e:
                print("verify_args catch err: ", traceback.format_exc())
                if release:
                    return f(*args_bak, **kwargs_bak)
                else:
                    return False, str(e)
            return f(*args_dict.values())

        return decorated_func

    return decorator
    
    
@validator_args(rules=rules_example, strip=True)  # 姿勢 3
def todo(a, b, c, d, e, f, g, h, i, j, k, l, m):
    return True, {"a": a, "b": b, "c": c, "d": d, "e": e, "f": f, "g": g, "h": h, "i": i, "j": j, "k": k, "l": l,
                  "m": m}
                  

哎,就這樣吧,打包一下,隨便選吧,愛用哪個用哪個,反正我都寫出來了.簡單說就是:

validator_func 針對flask的request.json/requests.values的參數(shù)校驗以及修改,修改的方式有限,可以自己控制

validator_wrap 是針對flask route的裝飾器,針對request.json/requests.values的參數(shù)校驗,只是校驗,當(dāng)然校驗的方式可以自己寫擴(kuò)展

validator_args 針對普通函數(shù)的參數(shù)校驗以及修改,注意不要使用python傳參的高級特性(一個參數(shù)對應(yīng)多個值),這個方法可以脫離flask使用,所以如果需要就直接copy過去吧.

嗯,最后還是分享一下到git上吧, https://github.com/aleimu/flask-validator 喜歡的點個star.

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/42796.html

相關(guān)文章

  • 類型系統(tǒng)-前端進(jìn)化里程碑

    摘要:這些優(yōu)勢,其實都是類型系統(tǒng)所帶來的強(qiáng)類型語言所具有的開發(fā)優(yōu)勢,無論是在開發(fā)體驗還是后期項目維護(hù)上,都要優(yōu)于目前的。 大半夜的JavaScript Weekly發(fā)來賀電:TypeScript 2.0 Final Released! 沒錯,繼Angular2發(fā)布之后,TypeScript今天也發(fā)布了2.0版本,這不禁讓我浮想一番。如果要說TS和JS最明顯的差別,我想一定是Type Syst...

    wangzy2019 評論0 收藏0
  • 這兩年多我寫PHP業(yè)務(wù)代碼方式是如何進(jìn)化

    摘要:曾今誰都有過迷茫期,下面是我開始開發(fā)中,不斷改變的代碼組織方式。 曾今 誰都有過迷茫期,下面是我開始PHP開發(fā)中,不斷改變的代碼組織方式。 初期:所有代碼一股腦控制器controller 曾今只是簡單的理解MVC 中期:業(yè)務(wù)代碼抽象一部分到模型層model 開始覺得model層是否該做點什么了 后期:業(yè)務(wù)代碼控制器,模型層只寫db的curd方法 復(fù)雜的業(yè)務(wù)代碼使contro...

    qqlcbb 評論0 收藏0
  • python生成器、迭代器、裝飾器分別是什么意思呢?

      python中的生成器、迭代器、裝飾器分別是什么意思呢?具體的含義,一些其具體的用途,下面小編就給大家詳細(xì)的解答下?! ∫?、裝飾器  由于一個函數(shù)能實現(xiàn)一種功能,現(xiàn)在想要在不改變其代碼的情況下,讓這個函數(shù)進(jìn)化一下,即能保持原來的功能,還能有新的"技能",怎么辦?  現(xiàn)已經(jīng)存在一個自定義的函數(shù)func1  deffunc1():   print('hello,worl...

    89542767 評論0 收藏0
  • 使用swagger 生成 Flask RESTful API

    摘要:指定篩選條件選擇合適的狀態(tài)碼應(yīng)答中,需要帶一個很重要的字段。返回結(jié)果針對不同操作,服務(wù)器向用戶返回的結(jié)果應(yīng)該符合以下規(guī)范。如果狀態(tài)碼是,就應(yīng)該向用戶返回出錯信息。 什么是 RESTful 什么是REST REST(英文:Representational State Transfer,又稱具象狀態(tài)傳輸)是Roy Thomas Fielding博士于2000年在他的博士論文 中提出來的一種...

    printempw 評論0 收藏0
  • 生成器進(jìn)化到協(xié)程 Part 1

    摘要:生成器用于定義生成器函數(shù)只要存在該函數(shù)必定是一個生成器調(diào)用該函數(shù)返回一個生成器讓一個生成器前進(jìn)使用使一個生成器前進(jìn)到下一個語句處,并將產(chǎn)出值作為其返回值。 前言 這篇文章大部分來自 David Beazley 在 PyCon 2014 的 PPT 《Generators: The Final Frontier》。這個PPT很長而且非常燒腦,建議在閱讀前應(yīng)了解 Python 的生成器與攜...

    lemon 評論0 收藏0

發(fā)表評論

0條評論

xfee

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<