关于服务器数据验证,一种比较优雅简便的Python解决方法
2013-11-12 23:01
591 查看
这两天整服务器代码遇到如题所说问题,不得已上了chinaunix发了个帖子,寻找一种比较好的解决方式,最后找到了一种比较好的方法,中间学到了挺多东西,现记录在此。
原帖地址:http://bbs.chinaunix.net/thread-4111060-1-1.html
感谢@Hadron74 跨生物学界和编程界的博士后,业余时间也翻译了一本python书《Python
for Bioinformatics》,搞生物学的pythoner可以去读一下~~
他的博客地址是:http://blog.sciencenet.cn/home.php?mod=space&uid=565112
原抛出来的问题是这样的:
拿一个具体的例子来说吧:
第一代原型函数是这样的:
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
'''
这是一条路由,假如是IP+"/test/"就可以访问到此函数。然后其form中带了三个参数:lat,lon,id。
'''
lat = request.form.get('LAT')
lon = request.form.get('LON')
id = request.form.get('OBJECT_ID')
#接下来每个参数都要处理一遍,非常蛋疼的行为!
try:
lat = float(lat)
except:
error = ERROR_LAT
return error
try:
lon = float(lon)
except:
error = ERROR_LON
return error
try:
id = ObjectId(id)
except:
error = ERROR_ID
return error
do_something()
复制代码
这样的话如果参数一多的话,首先好几十行处理类型转换的代码,而且如果路由多了,那么这些冗余代码量是很可观的,因此这个函数演化诞生了第二代原型,如下:
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
lat = request.form.get('LAT')
lon = request.form.get('LON')
id = request.form.get('OBJECT_ID')
#这种写法稍微好些,等于用check_format先把风险吃掉了,但是无法更新这里的lat,lon,id等值,所以还要下面再来一次
is_ok, error = check_format(lat=lat, lon=lon, id=id)
if not is_ok:
return error
lat = float(lat)
lon = float(lon)
id = ObjectId(id)
do_something()
@classmethod
def check_format(lat=None, lon=None, id=None):
,,,
本方法因为是与处理一个数据类中的值相关,所以与上面的方法不在同一个py文件中。
如果我的项目是mvc架构的话,那么它是应该放在model层的,上面的函数放在view层。
,,,
ret = True
error = ''
if lat is not None:
try:
lat = float(lat)
except:
error = ERROR_LAT
return False, error
if lon is not None:
try:
lon = float(lon)
except:
error = ERROR_LON
return False, error
if id is not None:
try:
id = ObjectId(id)
except:
error = ERROR_ID
return False, error
return ret, error
复制代码
第二代原型函数就是这样,不过你也看到了,在check_format()之后,还要自己再转一次,对于一个写代码喜欢追求美感的码农来说,这显然有点儿破坏美感,如果能够同时一次就改变了原函数中的值就好了,无奈精力和python造诣有限一时想不出好方法,因此特来求助于各位pythoner高手,希望解决这个需求,小弟先谢过了
待续。。。。
PS:
今日光棍节,愿天下程序猿光棍早日“脱光”
使用的时候,只需要把新的句柄的开关加入到__routes__中,然后,定义下对应的方法就好了。
(风险:如果有几个检测是非常相似的,最好在检测时候仔细处理,免得被先检测的方法误"诊"了)
class MetaRouter(object):
def __init__(self):
self.__routes__ = ('lat', 'lon', 'id') # define the head of handler
def test_route(self, content):
handle = None
for index in xrange(len(self.__routes__)):
methodName = self.__routes__[index] + "_handler"
handler = getattr(self, methodName)
if handler(content) == True:
print("Current is %s", self.__routes__[index])
break
# below is the dosomething():
print "all is done.\n", "=" * 80
def lat_handler(self, content): # handler for lat
try:
float(content)
return True
except:
return False
def lon_handler(self, content): # handler for lon
try:
int(content)
return True
except:
return False
def id_handler(self, content): # handler for id
try:
return True
except:
return False
def main():
route = MetaRouter()
route.test_route("33") # verify lan
route.test_route("3.14") # verify lon
route.test_route("id=9") # verify id
if __name__ == '__main__':
main()
我写的只是一个思路,你可以用自定义函数的方法,处理任何你需要的预处理参数问题,如果你看懂了我的程序,不难实现。
在程序中只需要维护一个字典就能完成所有的处理。当然你也可以用一个try块把这部分程序封装在check_form函数中,用values做返回值,这样就能截获错误信息。代码我就不写了。
你的代码虽然懂了,但是实际操作起来仍然不好操作,尝试了几次都没找到比较好的实际操作方法,而且那些lat,lon,id在下面的do_something()阶段还要接着使用的
我想了一下,大概实现思路是这样的:
第一阶段:
lat, is_ok, error = check_format(lat='LAT')
if not_is_ok:
return error
lon, is_ok, error = check_format(lon='LON')
if not_is_ok:
return error
id, is_ok, error = check_format(id='OBJECT_ID')
if not_is_ok:
return error
lon = 123
lat = 321
这是分开写的,然后需要进化到把其变成
for item in items:
?, is_ok, error = check_format(?)
if not is_ok:
return error
lon = 123
lat = 321
关键是?这里怎么填写才能给lon,lat,id赋上值?而且下面还要用到lon和lat,不知您知道怎么实现吗?
这里关于check_format()应该不难,只要传入对应参数,做相应处理即可。
我觉得只要功能逻辑划分清楚,代码保持适当的冗余可以简化问题。把test_route的一堆“if”转移到check_format又能改变什么?反而让代码更难懂。大概意思如下
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
lat, error = parse_float(request.form.get('LAT'))
if lat is None:
return error
lon, error = parse_float(request.form.get('LON'))
if lon is None:
return error
object_id, error = parse_object_id(request.form.get('OBJECT_ID'))
if object_id is None:
return error
do_something()
def parse_float(param):
pass
def parse_object_id(param):
pass
复制代码
我项目使用的是Flask,其有一个WTForms,不过我嫌建造太多Form太麻烦,而且有些限制,没有首先考虑。
你这里用全局变量tmp不是一个鲁棒的办法,容易出问题。原因一样,全局变量可能导致崩溃。
我不理解你为什么说直接调用函数会多次执行,这是怎么回事呢?为什么哑员参数传递不成?
你可以试试传函数参数的方法。代码如下:
class Protocol(Object):
LON = 'lon'
LAT = 'lat'
ID = 'id'
def _LAT_LON(tmp):
try:
value = float(tmp)
except:
error = Error.ERROR_LAT_LON
return False, error, tmp
return True, '', value
def _ID(tmp,others="None"):
pass
protocol_dict = {
Protocol.LON:(_LON_LAT,[])
Protocol.LAT:(_LON_LAT,[])
Protocol.ID:(_ID,["others"]) # 定义函数,和哑员参数
}
def check_protocol(arg, args):
value = args.get(arg)
func = protocol_dict[arg][0]
others = protocol_dict[arg][1]
if func is not '':
return func(value,*others) # 函数调用,加哑员
else:
return True, '', value
复制代码
回复 9# Hadron74
回复 8# yjphhw
上面那样感觉已经不错了,但是实际使用起来,还是比较麻烦,甚至还不如我最开始写的更简洁明了呢,后来想了一下,发现还有一个方法可以继续优化,并且看起来非常的让人舒畅,这就是我理想中的code了。现贴之如下:
check_format()函数是这样定义的:
def check_format(arg, value):
func = protocol_dict[arg][0]
if func is '':
raise CheckFormatException(0)
is_ok, error, result = func(value)
if not is_ok:
raise CheckFormException(error)
return result
复制代码
如果format信息不符合要求,直接甩出CheckFormatException错误,此错误里面包含错误码,如果正常就返回转型后的数据。
新建了一个protocol类,里面放着那些协议参数名,如下:
class Protocol(Object):
LON = 'lon'
LAT = 'lat'
ID = 'id'
class CheckFormatException(Exception)
def __init__(self, error_code):
Exception.__init__(self, error_code)
self.error = error_code
def _LAT_LON(value):
try:
value = float(value)
except:
error = Error.ERROR_LAT_LON
return False, error, value
return True, '', value
def _ID(id):
try:
id = ObjectId(id)
except:
error = Error.ERROR_ID
return False, error, id
return True, '', id
protocol_dict = {
Protocol.LON: (_LAT_LON, []), #一不留神又写错了,_LAT_LON写成_LAT_LON()了,多谢楼下斧正
Protocol.LAT: (_LAT_LON, []),
Protocol.ID: (_ID, [])
}
复制代码
在视图View层,你只需这样即可:
@app.route('/test/')
def test():
forms = request.forms
try:
lon = check_format(LON, forms.get(LON))
lat = check_format(LAT, forms.get(LAT))
id = check_format(ID, forms.get(ID))
exception CheckFormatException, e:
return e.error
#lon and lat尽情使用吧,类型已经转换过来了
复制代码
所有的都是这么简单,给check_format()传递一个参数名,一个value
这里要多谢大家给予的帮助,尤其是@Hadron74兄弟,谢谢。
本帖完,谢谢观赏。
原帖地址:http://bbs.chinaunix.net/thread-4111060-1-1.html
感谢@Hadron74 跨生物学界和编程界的博士后,业余时间也翻译了一本python书《Python
for Bioinformatics》,搞生物学的pythoner可以去读一下~~
他的博客地址是:http://blog.sciencenet.cn/home.php?mod=space&uid=565112
原抛出来的问题是这样的:
1楼:Sasoritattoo
要求是这样的,有一个项目是手机应用客户端与服务器通信,但是每次网络来的请求都会有很多的字符串参数需要转换,而且需要验证其基本信息是否符合基本格式要求,如果不符合会返回错误码给客户端,符合了就返回正常的数据。拿一个具体的例子来说吧:
第一代原型函数是这样的:
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
'''
这是一条路由,假如是IP+"/test/"就可以访问到此函数。然后其form中带了三个参数:lat,lon,id。
'''
lat = request.form.get('LAT')
lon = request.form.get('LON')
id = request.form.get('OBJECT_ID')
#接下来每个参数都要处理一遍,非常蛋疼的行为!
try:
lat = float(lat)
except:
error = ERROR_LAT
return error
try:
lon = float(lon)
except:
error = ERROR_LON
return error
try:
id = ObjectId(id)
except:
error = ERROR_ID
return error
do_something()
复制代码
这样的话如果参数一多的话,首先好几十行处理类型转换的代码,而且如果路由多了,那么这些冗余代码量是很可观的,因此这个函数演化诞生了第二代原型,如下:
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
lat = request.form.get('LAT')
lon = request.form.get('LON')
id = request.form.get('OBJECT_ID')
#这种写法稍微好些,等于用check_format先把风险吃掉了,但是无法更新这里的lat,lon,id等值,所以还要下面再来一次
is_ok, error = check_format(lat=lat, lon=lon, id=id)
if not is_ok:
return error
lat = float(lat)
lon = float(lon)
id = ObjectId(id)
do_something()
@classmethod
def check_format(lat=None, lon=None, id=None):
,,,
本方法因为是与处理一个数据类中的值相关,所以与上面的方法不在同一个py文件中。
如果我的项目是mvc架构的话,那么它是应该放在model层的,上面的函数放在view层。
,,,
ret = True
error = ''
if lat is not None:
try:
lat = float(lat)
except:
error = ERROR_LAT
return False, error
if lon is not None:
try:
lon = float(lon)
except:
error = ERROR_LON
return False, error
if id is not None:
try:
id = ObjectId(id)
except:
error = ERROR_ID
return False, error
return ret, error
复制代码
第二代原型函数就是这样,不过你也看到了,在check_format()之后,还要自己再转一次,对于一个写代码喜欢追求美感的码农来说,这显然有点儿破坏美感,如果能够同时一次就改变了原函数中的值就好了,无奈精力和python造诣有限一时想不出好方法,因此特来求助于各位pythoner高手,希望解决这个需求,小弟先谢过了
待续。。。。
PS:
今日光棍节,愿天下程序猿光棍早日“脱光”
2楼:icymirror
我也是刚学习Python不久,最近刚刚在看metaclass相关的东西,也许下面的方法是你需要的。使用的时候,只需要把新的句柄的开关加入到__routes__中,然后,定义下对应的方法就好了。
(风险:如果有几个检测是非常相似的,最好在检测时候仔细处理,免得被先检测的方法误"诊"了)
class MetaRouter(object):
def __init__(self):
self.__routes__ = ('lat', 'lon', 'id') # define the head of handler
def test_route(self, content):
handle = None
for index in xrange(len(self.__routes__)):
methodName = self.__routes__[index] + "_handler"
handler = getattr(self, methodName)
if handler(content) == True:
print("Current is %s", self.__routes__[index])
break
# below is the dosomething():
print "all is done.\n", "=" * 80
def lat_handler(self, content): # handler for lat
try:
float(content)
return True
except:
return False
def lon_handler(self, content): # handler for lon
try:
int(content)
return True
except:
return False
def id_handler(self, content): # handler for id
try:
return True
except:
return False
def main():
route = MetaRouter()
route.test_route("33") # verify lan
route.test_route("3.14") # verify lon
route.test_route("id=9") # verify id
if __name__ == '__main__':
main()
3楼:Hadron74
本帖最后由 Hadron74 于 2013-11-11 14:31 编辑 回复 1# Sasoritattoo n 你可以充分利用字典的功能,用维护一个字典,记录所需的format的格式和错误代码。另外再用一个字典保存返回值。这个程序就简洁多了,没有冗余代码了。 具体程序如下: class ObjectId(str): def __init__(self,obj): str.__init__(self,obj) # This is the dictionary you need to support key_format = {"LAT":(float,1)\ ,"LON":(float,2)\ ,"ObjectId":(ObjectId,3)\ } def test_route(requestForm,key_format): values = {} for key in key_format: value = requestForm[key] #value = request.form.get(key) # You can use the line in your real function try: values[key] = key_format[key][0](value) except: raise ValueError("DATA FORMAT ERROR NO:%d"% (key_format[key][1],)) print values # to store the converted data #do_something() rf={"LAT":"12.0","LON":"2.0","ObjectId":"This is an example"} test_route(rf,key_format) rf={"LAT":"12.0","LON":"ERROR2.0","ObjectId":"This is an example"} test_route(rf,key_format) 复制代码 结果: $python test_route.py {'LAT': 12.0, 'LON': 2.0, 'ObjectId': 'This is an example'} Traceback (most recent call last): File "test_route.py", line 33, in <module> test_route(rf,key_format) File "test_route.py", line 20, in test_route raise ValueError("DATA FORMAT ERROR NO:%d"% (key_format[key][1],)) ValueError: DATA FORMAT ERROR NO:2 复制代码 |
4楼:Sasoritattoo
回复 3# Hadron74 其实,不只是做类型检查这么简单,类型检查只是一部分,我是希望通过check_format()方法实现预处理一下参数,不符合就返回错误,符合的话下面就直接用了。 |
5楼:Sasoritattoo
回复 2# icymirror 谢谢,不太能满足我的需求。 |
6楼:Hadron74
回复 4# Sasoritattoo我写的只是一个思路,你可以用自定义函数的方法,处理任何你需要的预处理参数问题,如果你看懂了我的程序,不难实现。
在程序中只需要维护一个字典就能完成所有的处理。当然你也可以用一个try块把这部分程序封装在check_form函数中,用values做返回值,这样就能截获错误信息。代码我就不写了。
7楼:Sasoritattoo
回复 6# Hadron74你的代码虽然懂了,但是实际操作起来仍然不好操作,尝试了几次都没找到比较好的实际操作方法,而且那些lat,lon,id在下面的do_something()阶段还要接着使用的
我想了一下,大概实现思路是这样的:
第一阶段:
lat, is_ok, error = check_format(lat='LAT')
if not_is_ok:
return error
lon, is_ok, error = check_format(lon='LON')
if not_is_ok:
return error
id, is_ok, error = check_format(id='OBJECT_ID')
if not_is_ok:
return error
lon = 123
lat = 321
这是分开写的,然后需要进化到把其变成
for item in items:
?, is_ok, error = check_format(?)
if not is_ok:
return error
lon = 123
lat = 321
关键是?这里怎么填写才能给lon,lat,id赋上值?而且下面还要用到lon和lat,不知您知道怎么实现吗?
这里关于check_format()应该不难,只要传入对应参数,做相应处理即可。
8楼:yjphhw
你可以通过表单来解决。看看表单,建立一个表单,然后,直接用表单的验证。 |
9楼:Hadron74
回复 7# Sasoritattoo 如果你非要直接用变量名,就把它们定义到globals里吧,不过该global变量不是好的编程,有崩溃的危险。(这里改了一版贴出来) class ObjectId(str): def __init__(self,obj): str.__init__(self,obj) # This is the dictionary you need to support key_format = {"LAT":(float,1,"lat")\ ,"LON":(float,2,"lon")\ ,"ObjectId":(ObjectId,3,"object")\ } def test_route(requestForm,key_format): def check_format(requestForm,key_format): values = {} for key in key_format: value = requestForm[key] #value = request.form(key) # You can use the line in your real function try: values[key_format[key][2]] = key_format[key][0](value) except: values = (key,key_format[key][1]) return values values = check_format(requestForm,key_format) if type(values) != type({}): key, err_number = values # deal something for the error print key,err_number, "heihei" return globals().update(values) #do_something() print lat, "xixixixi" print object, "hahaha" rf={"LAT":"12.0","LON":"2.0","ObjectId":"This is an example"} test_route(rf,key_format) test_route(rf,key_format) rf={"LAT":"12.0","LON":"ERROR2.0","ObjectId":"This is an example"} test_route(rf,key_format) 复制代码 结果 $python test_route.py 12.0 xixixixi This is an example hahaha LON 2 heihei 复制代码 还有一种方法是用类的属性函数,这里就不写了,但是lat前需要加个classname,用classname.lat 参考http://stackoverflow.com/questio ... -variable-in-python 不过我觉得最好的方法,也是最简单就是在后续程序中用values["lat"]来替代lat; 你说呢? |
10楼:timespace
回复 7# Sasoritattoo我觉得只要功能逻辑划分清楚,代码保持适当的冗余可以简化问题。把test_route的一堆“if”转移到check_format又能改变什么?反而让代码更难懂。大概意思如下
@app.route('/test', methods = ['GET', 'POST'])
def test_route():
lat, error = parse_float(request.form.get('LAT'))
if lat is None:
return error
lon, error = parse_float(request.form.get('LON'))
if lon is None:
return error
object_id, error = parse_object_id(request.form.get('OBJECT_ID'))
if object_id is None:
return error
do_something()
def parse_float(param):
pass
def parse_object_id(param):
pass
复制代码
11楼:Sasoritattoo
回复 8# yjphhw我项目使用的是Flask,其有一个WTForms,不过我嫌建造太多Form太麻烦,而且有些限制,没有首先考虑。
12楼:Sasoritattoo
回复 9# Hadron74 这种方式也不符合,global变量是下策 |
13楼:Sasoritattoo
回复 10# timespace 太多的冗余代码会影响代码的观看,写程序不是堆砌代码,在我看来是思维逻辑的展现,尽可能的简洁,一下子就能看到逻辑,某一层有某一层的逻辑,不要混淆在一起。 |
14楼:Sasoritattoo
回复 10# timespace 回复 9# Hadron74 回复 8# yjphhw 想来想去,每种思路都是比较麻烦,不能够很好的达到我想要的效果。不过我最后我采用了一种在我看来稍微好些的思路,各位可以看一下: check_format()函数是这样定义的 @classmethod def check_format(cls, forms, args): ret = True error = '' ret_dict = {} if len(args) == 0: return ret, error, ret_dict for arg in args: is_ok, error, value = check_protocol(arg, forms) if not is_ok: return is_ok, error, ret_dict ret_dict[arg] = value return ret, error, ret_dict 复制代码 另外我新建了一个protocol类,里面放着那些协议参数名,如下: class Protocol(Object): LON = 'lon' LAT = 'lat' ID = 'id' def _LAT_LON(): try: value = float(tmp) except: error = Error.ERROR_LAT_LON return False, error, tmp return True, '', value def _ID(): pass protocol_dict = { Protocol.LON:'_LON()', Protocol.LAT:'_LAT()', Protocol.ID:'_ID()' } tmp = '' def check_protocol(arg, args): value = args.get(arg) global tmp tmp = value func = protocol_dict[arg] if func is not '': return eval(func) else: return True, '', value 复制代码 在视图View层,你只需这样即可: @app.route('/test/') def test(): forms = request.args #或者request.forms args = [Protocol.LAT, Protocol.LAT, Protocol.ID] is_ok, error, DICTS = check_format(forms, args) if not is_ok: return error lon = DICTS[Protocol.LON] lat = DICTS[Protocol.LAT] id = DICTS[Protocol.ID] 复制代码 这样的好处是你在视图函数里只需要知道check_format()即可,按照这个流程来就行了,知一知百,里面怎么实现不用关心,这样对于将来代码的维护者来说也是轻巧很多,很容易懂,而且减少了很多代码量,非常容易就看清框架思路。 目前,在我看来,这是目前来讲我感觉比较好些的解决思路。 关于check_protocol部分,如果能够实现通过eval执行函数并传递参数就更好了,只可惜我不知道怎么操作,如果有懂的人还请告知一下,至于protocol_dict中value值使用的是字符串,是担心直接函数的话会被多次执行。 如果有不同意见,欢迎继续交流哈~~ |
15楼:Hadron74
回复 14# Sasoritattoo你这里用全局变量tmp不是一个鲁棒的办法,容易出问题。原因一样,全局变量可能导致崩溃。
我不理解你为什么说直接调用函数会多次执行,这是怎么回事呢?为什么哑员参数传递不成?
你可以试试传函数参数的方法。代码如下:
class Protocol(Object):
LON = 'lon'
LAT = 'lat'
ID = 'id'
def _LAT_LON(tmp):
try:
value = float(tmp)
except:
error = Error.ERROR_LAT_LON
return False, error, tmp
return True, '', value
def _ID(tmp,others="None"):
pass
protocol_dict = {
Protocol.LON:(_LON_LAT,[])
Protocol.LAT:(_LON_LAT,[])
Protocol.ID:(_ID,["others"]) # 定义函数,和哑员参数
}
def check_protocol(arg, args):
value = args.get(arg)
func = protocol_dict[arg][0]
others = protocol_dict[arg][1]
if func is not '':
return func(value,*others) # 函数调用,加哑员
else:
return True, '', value
复制代码
16楼:Sasoritattoo
回复 15# Hadron74 使用tmp是不得已而用之,的确是很容易出问题的,也不符合OO原则,多亏了你提供的这个办法, 效果很好,多谢。 至于你说“我不理解你为什么说直接调用函数会多次执行?”其实是我使用eval()方法执行,不转成str的话,我在函数后加了(),所以被执行了一遍。最根本原因还是我对python有些特性不熟悉。 看了你的代码,也明白了,原来函数作为一个对象保存起来是这样保存的。再谢。 |
17楼:Sasoritattoo
回复 10# timespace回复 9# Hadron74
回复 8# yjphhw
上面那样感觉已经不错了,但是实际使用起来,还是比较麻烦,甚至还不如我最开始写的更简洁明了呢,后来想了一下,发现还有一个方法可以继续优化,并且看起来非常的让人舒畅,这就是我理想中的code了。现贴之如下:
check_format()函数是这样定义的:
def check_format(arg, value):
func = protocol_dict[arg][0]
if func is '':
raise CheckFormatException(0)
is_ok, error, result = func(value)
if not is_ok:
raise CheckFormException(error)
return result
复制代码
如果format信息不符合要求,直接甩出CheckFormatException错误,此错误里面包含错误码,如果正常就返回转型后的数据。
新建了一个protocol类,里面放着那些协议参数名,如下:
class Protocol(Object):
LON = 'lon'
LAT = 'lat'
ID = 'id'
class CheckFormatException(Exception)
def __init__(self, error_code):
Exception.__init__(self, error_code)
self.error = error_code
def _LAT_LON(value):
try:
value = float(value)
except:
error = Error.ERROR_LAT_LON
return False, error, value
return True, '', value
def _ID(id):
try:
id = ObjectId(id)
except:
error = Error.ERROR_ID
return False, error, id
return True, '', id
protocol_dict = {
Protocol.LON: (_LAT_LON, []), #一不留神又写错了,_LAT_LON写成_LAT_LON()了,多谢楼下斧正
Protocol.LAT: (_LAT_LON, []),
Protocol.ID: (_ID, [])
}
复制代码
在视图View层,你只需这样即可:
@app.route('/test/')
def test():
forms = request.forms
try:
lon = check_format(LON, forms.get(LON))
lat = check_format(LAT, forms.get(LAT))
id = check_format(ID, forms.get(ID))
exception CheckFormatException, e:
return e.error
#lon and lat尽情使用吧,类型已经转换过来了
复制代码
所有的都是这么简单,给check_format()传递一个参数名,一个value
这里要多谢大家给予的帮助,尤其是@Hadron74兄弟,谢谢。
本帖完,谢谢观赏。
18楼:Hadron74
本帖最后由 Hadron74 于 2013-11-12 23:26 编辑 回复 17# Sasoritattoo 我也是理想主义者,看了楼主的代码,觉得有很多可取的地方,但是try块嵌套用得太多了,而且,像一个float函数都得重写一个函数,太冗余了。我试着改写了你的代码: def check_format(arg, value): func = protocol_dict[arg][0] others = protol_dict[arg][1] try: result = func(value,*others) except: raise CheckFormException(protocol_dict[arg][2]) # 在这里根据不同arg抛出错误码,在字典中定义。 return result 复制代码 class Protocol(Object): #个人觉得你这一层类的设计没有必要,可以精简掉 LON = 'lon' LAT = 'lat' ID = 'id' class CheckFormatException(Exception) def __init__(self, error_code): Exception.__init__(self, error_code) self.error = error_code #这个设计不错,学习了 protocol_dict = { Protocol.LON: (float, [],ERROR_float), # 这里直接用转换函数,没有必要再嵌套一层,而且注意函数对象后面不能有(),你的代码有误 Protocol.LAT: (float, [],ERROR_float), Protocol.ID: (ObjectID, [],ERROR_ID) } 复制代码 其他代码一样,是不是更简洁一点呢? |
19楼:Sasoritattoo
回复 18# Hadron74 的确更简洁,这一部分也确实有些冗余,不过,这毕竟是一个demo,实际项目中可不只是做类型转换,还有比如检测文本是否符合长度,不能太少也不能太多,而且每种文本的长度限制是不一样的。 比如,检查文本是否符合长度的函数: def _check_text_length(t, min_len, max_len): if min_len <= ken(t) <= max_len: return True, '', t return False, '', t 关于协议类去掉的考虑,如果去掉的话,整个协议文本散落在整个项目中,到时候改起来非常不好改,必须全局唯一性,所以,存在是必要的。 其实,实际中我原本是每个协议对应一个check_format()方法,demo就是随便举的例子,但是你说这里有冗余,也的确,想了一下,现在改掉了冗余。 参考了你上面的做法,不过仍然是使用了自定义的函数,只不过分为_check_format_float(v), _check_format_int(v), _check_format_text(t, min_len, max_len),为其分了几个大类,错误码就找你说得写在了protocol_dict[]中了。我的协议挺多的,这样一精简,少了一大半代码,看起来也清爽多了。Hadron74兄,劳烦看看是否有比我的更好方法?欢迎交流斧正 |
20楼:Hadron74
回复 19# Sasoritattoo 如果只维护一个字典表,程序的代码量,会好很多。我也没有什么可说的了。有一个技巧可能提高你可变哑员的编程。 就是用一个列表(诸如前面说的)的可变哑员,用一个字典用于可改变顺序的哑员。 如 def func(a,b,c,d=None,e=1): print a,b,c,d,e arg=[1.5,"a",1] # 定义一个哑员变量表 kwarg={"d":None,"e":2} #定义一个字典哑员表 func_dict={"func":(func,arg,kwarg)} #把函数对象放在字典里 func_dict["func"][0](*func_dict["func"][1],**func_dict["func"][2]) #函数调用 复制代码 具体函数哑员及调用的例子,参考我翻译的文稿:http://bbs.sciencenet.cn/blog-565112-523776.html |
21楼:Sasoritattoo
回复 20# Hadron74 受教了,谢谢! 已经加了哑元键参数作为默认值。 如果没猜错的话,@Hadron74兄竟然是跨生物信息学界和编程界的博士后,而且自己业余时间翻译了一本python教材书,非常的令人倾佩! |
相关文章推荐
- 关于从服务器获取的JSON数据为OC关键字的解决方法(id, description)
- 解决"链接服务器 '(null)' 的 OLE DB 访问接口 'STREAM' 返回了对列 '[!BulkInsert].fieldname' 无效的数据"的一种替换方法
- 有关于在myeclipse中java向服务器发送请求返回数据有中文乱码的一种情况及解决
- Oracle11g客户端连接服务器很慢的一种解决方法(登录验证方式导致)
- 关于flask表单验证json数据不通过总是返回False的解决方法(flask wtforms: Validation always false)
- 关于在xp系统下CTreeCtrl控件不显示图标的一种解决方法
- Android:解决客户端从服务器上获取数据乱码的方法
- asp.net 2.0关于NavigateUrl中绑定Eval()方法时出现"服务器标记的格式不正确"的解决方法
- 关于MATLAB中xlswrite函数写数据出现服务器异常情况的解决办法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于ECSHOP模板架设的服务器php版本过高报错的解决方法集合
- 关于“未指定的错误”的问题 的比较正解的解决方法
- 关于FTP服务器上传下载的代码中文乱码的解决方法
- 服务器数据丢失的紧急解决方法
- 跨服务器post数据失败:验证视图状态 MAC 失败。如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 validationKey 和验证算法。的解决办法
- Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库 自定义日志记录功能,按日记录,很方便 C#常量和字段以及各种方法的语法总结 类型,对象,线程栈,托管堆在运行时的关系,以及clr如何调用静态方法,实例方法,和虚方法 asp.net webapi 自定义身份验证
- 关于C#代码用F12转到定义时,总是显示从元数据的解决方法
- 关于ORA-01034和ORA-27101的一种解决方法
- 关于【对象“***.rem”已经断开连接或不在服务器上】异常的解决方法