免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 9241 | 回复: 21
打印 上一主题 下一主题

求一个函数的写法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-11-11 11:29 |只看该作者 |倒序浏览
15可用积分
本帖最后由 Sasoritattoo 于 2013-11-11 15:12 编辑

要求是这样的,有一个项目是手机应用客户端与服务器通信,但是每次网络来的请求都会有很多的字符串参数需要转换,而且需要验证其基本信息是否符合基本格式要求,如果不符合会返回错误码给客户端,符合了就返回正常的数据。

拿一个具体的例子来说吧:
第一代原型函数是这样的:

  1. @app.route('/test', methods = ['GET', 'POST'])
  2. def test_route():
  3.     '''
  4.     这是一条路由,假如是IP+"/test/"就可以访问到此函数。然后其form中带了三个参数:lat,lon,id。
  5.     '''
  6.     lat = request.form.get('LAT')
  7.     lon = request.form.get('LON')
  8.     id = request.form.get('OBJECT_ID')

  9.      #接下来每个参数都要处理一遍,非常蛋疼的行为!
  10.     try:
  11.         lat = float(lat)
  12.     except:
  13.         error = ERROR_LAT
  14.         return error

  15.     try:
  16.         lon = float(lon)
  17.     except:
  18.         error = ERROR_LON
  19.         return error
  20.    
  21.     try:
  22.         id = ObjectId(id)
  23.     except:
  24.         error = ERROR_ID
  25.         return error

  26.     do_something()
复制代码
这样的话如果参数一多的话,首先好几十行处理类型转换的代码,而且如果路由多了,那么这些冗余代码量是很可观的,因此这个函数演化诞生了第二代原型,如下:

  1. @app.route('/test', methods = ['GET', 'POST'])
  2. def test_route():
  3.     lat = request.form.get('LAT')
  4.     lon = request.form.get('LON')
  5.     id = request.form.get('OBJECT_ID')

  6.     #这种写法稍微好些,等于用check_format先把风险吃掉了,但是无法更新这里的lat,lon,id等值,所以还要下面再来一次
  7.     is_ok, error = check_format(lat=lat, lon=lon, id=id)
  8.     if not is_ok:
  9.         return error

  10.     lat = float(lat)
  11.     lon = float(lon)
  12.     id = ObjectId(id)

  13.     do_something()


  14. @classmethod
  15. def check_format(lat=None, lon=None, id=None):
  16.     ,,,
  17.     本方法因为是与处理一个数据类中的值相关,所以与上面的方法不在同一个py文件中。
  18.     如果我的项目是mvc架构的话,那么它是应该放在model层的,上面的函数放在view层。
  19.     ,,,
  20.     ret = True
  21.     error = ''
  22.     if lat is not None:
  23.         try:
  24.             lat = float(lat)
  25.         except:
  26.             error = ERROR_LAT
  27.             return False, error
  28.     if lon is not None:
  29.         try:
  30.             lon = float(lon)
  31.         except:
  32.             error = ERROR_LON
  33.             return False, error
  34.     if id is not None:
  35.         try:
  36.             id = ObjectId(id)
  37.         except:
  38.             error = ERROR_ID
  39.             return False, error

  40.     return ret, error
复制代码
第二代原型函数就是这样,不过你也看到了,在check_format()之后,还要自己再转一次,对于一个写代码喜欢追求美感的码农来说,这显然有点儿破坏美感,如果能够同时一次就改变了原函数中的值就好了,无奈精力和python造诣有限一时想不出好方法,因此特来求助于各位pythoner高手,希望解决这个需求,小弟先谢过了
待续。。。。

PS:
今日光棍节,愿天下程序猿光棍早日“脱光”

最佳答案

查看完整内容

回复 14# Sasoritattoo 你这里用全局变量tmp不是一个鲁棒的办法,容易出问题。原因一样,全局变量可能导致崩溃。我不理解你为什么说直接调用函数会多次执行,这是怎么回事呢?为什么哑员参数传递不成?你可以试试传函数参数的方法。代码如下:

论坛徽章:
0
2 [报告]
发表于 2013-11-11 11:29 |只看该作者
本帖最后由 Hadron74 于 2013-11-12 16:40 编辑

回复 14# Sasoritattoo

你这里用全局变量tmp不是一个鲁棒的办法,容易出问题。原因一样,全局变量可能导致崩溃。
我不理解你为什么说直接调用函数会多次执行,这是怎么回事呢?为什么哑员参数传递不成?
你可以试试传函数参数的方法。代码如下:
  1. class Protocol(Object):
  2.     LON = 'lon'
  3.     LAT = 'lat'
  4.     ID   = 'id'


  5. def _LAT_LON(tmp):
  6.     try:
  7.         value = float(tmp)
  8.     except:
  9.         error = Error.ERROR_LAT_LON
  10.         return False, error, tmp
  11.     return True, '', value

  12. def _ID(tmp,others="None"):
  13.     pass

  14. protocol_dict = {
  15.     Protocol.LON:(_LON_LAT,[])
  16.     Protocol.LAT:(_LON_LAT,[])
  17.     Protocol.ID:(_ID,["others"])                   # 定义函数,和哑员参数
  18. }


  19. def check_protocol(arg, args):
  20.     value = args.get(arg)
  21.     func = protocol_dict[arg][0]
  22.     others = protocol_dict[arg][1]
  23.     if func is not '':
  24.         return func(value,*others)            # 函数调用,加哑员
  25.     else:
  26.         return True, '', value
复制代码

论坛徽章:
4
白羊座
日期:2013-11-05 10:26:09冥斗士
日期:2015-11-17 14:19:55白银圣斗士
日期:2015-11-17 15:13:0815-16赛季CBA联赛之新疆
日期:2016-04-01 09:10:58
3 [报告]
发表于 2013-11-11 13:23 |只看该作者
本帖最后由 icymirror 于 2013-11-11 13:24 编辑

我也是刚学习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()

论坛徽章:
0
4 [报告]
发表于 2013-11-11 14:29 |只看该作者
本帖最后由 Hadron74 于 2013-11-11 14:31 编辑

回复 1# Sasoritattoo

n
    你可以充分利用字典的功能,用维护一个字典,记录所需的format的格式和错误代码。另外再用一个字典保存返回值。这个程序就简洁多了,没有冗余代码了。
具体程序如下:
  1. class ObjectId(str):
  2.     def __init__(self,obj):
  3.         str.__init__(self,obj)

  4. # This is the dictionary you need to support
  5. key_format = {"LAT":(float,1)\
  6.                 ,"LON":(float,2)\
  7.                 ,"ObjectId":(ObjectId,3)\
  8.                 }

  9. def test_route(requestForm,key_format):
  10.     values = {}
  11.     for key in key_format:
  12.         value = requestForm[key]
  13.         #value = request.form.get(key)  # You can use the line in your real function
  14.         try:
  15.             values[key] = key_format[key][0](value)
  16.         except:
  17.             raise ValueError("DATA FORMAT ERROR NO:%d"% (key_format[key][1],))

  18.     print values # to store the converted data
  19.     #do_something()
  20. rf={"LAT":"12.0","LON":"2.0","ObjectId":"This is an example"}

  21. test_route(rf,key_format)

  22. rf={"LAT":"12.0","LON":"ERROR2.0","ObjectId":"This is an example"}

  23. test_route(rf,key_format)
复制代码
结果:
  1. $python test_route.py
  2. {'LAT': 12.0, 'LON': 2.0, 'ObjectId': 'This is an example'}
  3. Traceback (most recent call last):
  4.   File "test_route.py", line 33, in <module>
  5.     test_route(rf,key_format)
  6.   File "test_route.py", line 20, in test_route
  7.     raise ValueError("DATA FORMAT ERROR NO:%d"% (key_format[key][1],))
  8. ValueError: DATA FORMAT ERROR NO:2
复制代码

论坛徽章:
0
5 [报告]
发表于 2013-11-11 15:43 |只看该作者
回复 3# Hadron74


    其实,不只是做类型检查这么简单,类型检查只是一部分,我是希望通过check_format()方法实现预处理一下参数,不符合就返回错误,符合的话下面就直接用了。

论坛徽章:
0
6 [报告]
发表于 2013-11-11 15:45 |只看该作者
回复 2# icymirror


    谢谢,不太能满足我的需求。

论坛徽章:
0
7 [报告]
发表于 2013-11-11 16:38 |只看该作者
本帖最后由 Hadron74 于 2013-11-11 16:43 编辑

回复 4# Sasoritattoo


    我写的只是一个思路,你可以用自定义函数的方法,处理任何你需要的预处理参数问题,如果你看懂了我的程序,不难实现。
在程序中只需要维护一个字典就能完成所有的处理。当然你也可以用一个try块把这部分程序封装在check_form函数中,用values做返回值,这样就能截获错误信息。代码我就不写了。

论坛徽章:
0
8 [报告]
发表于 2013-11-11 18:18 |只看该作者
回复 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()应该不难,只要传入对应参数,做相应处理即可。

论坛徽章:
0
9 [报告]
发表于 2013-11-11 18:28 |只看该作者
你可以通过表单来解决。看看表单,建立一个表单,然后,直接用表单的验证。

论坛徽章:
0
10 [报告]
发表于 2013-11-11 20:09 |只看该作者
回复 7# Sasoritattoo

如果你非要直接用变量名,就把它们定义到globals里吧,不过该global变量不是好的编程,有崩溃的危险。(这里改了一版贴出来)
  1. class ObjectId(str):
  2.     def __init__(self,obj):
  3.         str.__init__(self,obj)

  4. # This is the dictionary you need to support
  5. key_format = {"LAT":(float,1,"lat")\
  6.                 ,"LON":(float,2,"lon")\
  7.                 ,"ObjectId":(ObjectId,3,"object")\
  8.                 }

  9. def test_route(requestForm,key_format):

  10.     def check_format(requestForm,key_format):
  11.         values = {}
  12.         for key in key_format:
  13.             value = requestForm[key]
  14.             #value = request.form(key)  # You can use the line in your real function
  15.             try:
  16.                 values[key_format[key][2]] = key_format[key][0](value)
  17.             except:
  18.                 values = (key,key_format[key][1])
  19.        return values

  20.     values = check_format(requestForm,key_format)

  21.     if type(values) != type({}):
  22.         key, err_number = values
  23.         # deal something for the error
  24.         print key,err_number, "heihei"
  25.         return

  26.     globals().update(values)


  27.     #do_something()
  28.     print lat, "xixixixi"
  29.     print object, "hahaha"



  30. rf={"LAT":"12.0","LON":"2.0","ObjectId":"This is an example"}

  31. test_route(rf,key_format)

  32. test_route(rf,key_format)

  33. rf={"LAT":"12.0","LON":"ERROR2.0","ObjectId":"This is an example"}

  34. test_route(rf,key_format)

  35.                                                         
复制代码
结果
  1. $python test_route.py
  2. 12.0 xixixixi
  3. This is an example hahaha
  4. LON 2 heihei
复制代码
还有一种方法是用类的属性函数,这里就不写了,但是lat前需要加个classname,用classname.lat
参考http://stackoverflow.com/questio ... -variable-in-python
不过我觉得最好的方法,也是最简单就是在后续程序中用values["lat"]来替代lat;
你说呢?
   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP