Python递归中 return 代码陷阱

最近写接口测试程序中,需要查询多层嵌套字典中某个Key的值,查到则返回,查不到返回None,查询的Key可以是任意层次的Key,如 Value本身也是多层字典,或者Key已经是叶子结点。

思想:利用Python的递归思想,逐层深入遍历,最后返回结果值

最终的成品代码参考了一下博客内容:

http://www.cnblogs.com/hahaweixiaohenqingcheng/archive/2016/11/14/6062961.html#undefined

尝试多次后发现参考代码已经无法再深入优化,只能照搬:

 1 #获取字典中的objkey对应的值,适用于字典嵌套
 2 #targetDict:要查找的字典;serchKey:要查找的目标key
 3 #ret:递归过程中,向外部(上层)传送 return值。被查找目标在第几层,则返回几次ret
 4 #default:查不到符合的serchKey,就返回默认值None
 5 def dict_getValue(targetDict,serchKey,default=None):
 6     for k,v in targetDict.items():
 7         if k == serchKey:
 8             return v
 9         elif isinstance(v,dict):
10             ret = dict_getValue(v,serchKey,default)
11             if ret is not default: #ret与default=None不等,表示找到serchKey,则ret会作为返回值向上层返回。
12                 return ret
13     return default

测试数据,拼接在上面的代码里即可

1 if __name__ == ‘__main__‘:
2     targetDict ={"H": {"Ver": ["aaaa","bbbb"],"ACID": {‘kkk‘:"aaaaa"},"CInf": [100,2,1000]},
3                  "B": { "Login": {"Type": "LP","Name": "41SS676","Pwd": {‘aaa‘:"123456"},"ForToken": 1}}}
4     print (recursionSearch(targetDict,‘Name‘))

直接拼装上面代码即可

在成品之前,尝试过几种写法,都无法达到最终要求,进行了一些分析,现记录下来:

1、查找的Key只能是叶子结点,非叶子结点的无法实现查找,代码如下:

1 def recursionSearch(targetDict,serchKey):            #递归查找
2     for k,v in targetDict.items():
3         if isinstance(v,dict) :                      #值是字典元素,则递归处理
4             recursionSearch(v,serchKey)
5         elif k == serchKey:
6             pp=targetDict[k]
7             print (pp)
8             return pp

只考虑叶子结点是查询目标

结果:

print (recursionSearch(targetDict,‘kkk‘)) 看到打印出来的叶子结点的值正是我想要查找的Key=‘kkk‘的值‘aaaaaa’,

print (recursionSearch(targetDict,‘Name‘)) 换第二个分支里面的叶子结点,也能看到函数内打印结果41SS676是我想要的

应该是对的,Python输出:

41SS676
None
[Finished in 0.2s]

但为毛函数结果是None呢???

分析:

(1).代码确实能够达到叶子结点查找到目标键名的功能,但。。。还是尝试着换换思路吧

2、更换if条件,不会直接到叶子结点级别才开始查找

1 def recursionSearch(targetDict,serchKey):            #递归查找
2     for k,v in targetDict.items():
3         if k == serchKey:
4             return v
5         elif isinstance(v,dict) :                      #值是字典元素,则递归处理
6             recursionSearch(v,serchKey)

任一层查找,但代码还是错误的

分析:

  (2).这个程序最后一行只进行了递归调用,但是没有返回递归的值,导致一旦出现递归,则必然返回断档,结果必然是None。无return的函数返回值就是None,Python规定。

     参考《Python学习手册第4版》531页 “没有renturn语句的函数”

3、那就把递归调用的返回值也return一下

1 def recursionSearch(targetDict,serchKey):            #递归查找
2     for k,v in targetDict.items():
3         if k == serchKey:
4             return v
5         elif isinstance(v,dict) :                      #值是字典元素,则递归处理
6             ret = recursionSearch(v,serchKey)
7             return ret

return递归调用的结果

结果:这种代码只能按照第一个元素这条线深入递归下去,无论最终找到或者找不到目标值,都会结束递归。

这种没脑子的增加return直接导致的是:

(1).查找的Key在第一层第一个键值对的值中,且递归调用时,Key也在目标字典的第一个位置,能够返回正确值;

如:Key=‘H‘,Key=‘ACID’,Key=‘kkk’都能返回正确值,如果Key=‘B’,Key=‘CInf’只会返回None

(2).换句话说:for循环里只会使用第一对(k,v)

分析:

(1).必须增加一个处理方法,让程序能够在for循环中循环下去,不能只局限在第一对(k,v)中。

  主要就是用莫条件限制return ret是否执行,如果此return不执行,则for能继续循环下去

  如果ret是None就继续循环,如果ret不是None就证明找到目标,应该return ret,精简之后语句:if ret is not None: return ret

正向测试:

  print (recursionSearch(targetDict,‘H‘))                   #{‘Ver‘: [‘aaaa‘, ‘bbbb‘], ‘ACID‘: {‘kkk‘: ‘aaaaa‘}, ‘CInf‘: [100, 2, 1000]}

  print (recursionSearch(targetDict,‘ACID‘))              #{‘kkk‘: ‘aaaaa‘}

  print (recursionSearch(targetDict,‘kkk‘’))                #aaaaa

  print (recursionSearch(targetDict,‘Ver‘))                 #[‘aaaa‘, ‘bbbb‘]

  print (recursionSearch(targetDict,‘B‘))                    #{‘Login‘: {‘Type‘: ‘LP‘, ‘Name‘: ‘41SS676‘, ‘Pwd‘: {‘aaa‘: ‘123456‘}, ‘ForToken‘: 1}}

print (recursionSearch(targetDict,‘Login‘))               #{‘Type‘: ‘LP‘, ‘Name‘: ‘41SS676‘, ‘Pwd‘: {‘aaa‘: ‘123456‘}, ‘ForToken‘: 1}

  print (recursionSearch(targetDict,‘Pwd‘))                #{‘aaa‘: ‘123456‘}

  print (recursionSearch(targetDict,‘aaa‘))                 #123456

以上均能返回正确目标键的值

逆向测试:

  print (recursionSearch(targetDict,‘aaaaaa‘))  #None没有键属性是‘aaaaaa’的,只有一个键的值是‘aaaaaa’,测试函数是否是按键名查找

  print (recursionSearch(targetDict,‘B111‘))      #None

以上均能争取返回None

至此,从最初级错误程序,一步一步走到正确程序。

感谢我的同事 相开征  和我不厌其烦的讨论了一天,最终弄清楚了正确程序的原理,也一步一步分析清楚错误程序错在哪里,应该如何改进。

时间: 2024-10-03 14:46:33

Python递归中 return 代码陷阱的相关文章

如何调用另一个python文件中的代码

如何调用另一个python文件中的代码 无论我们选择用何种语言进行程序设计时,都不可能只有一个文件(除了"hello world"),通常情况下,我们都需要在一个文件中调用另外一个文件的函数呀数据等等,总之要操作其他文件中的代码,在java中,只要在同一个文件目录下,我们就不需要通过import导入,但是在Python中,我们就需要通过import来进行导入,这样我们才能应用其他文件中定义的函数和数据等代码. 对于刚接触python的我们,这是我们需要掌握的. 下面就以两个文件为例,例

python flask中的代码约定

在Python社区中有许多关于代码风格的约定.如果你写过一段时间Python了,那么也许对此已经有些了解. 我会简单介绍一下,同时给你一些URL链接,从中你可以找到关于这个话题的详细信息. 让我们提出一个PEP! PEP全称是“Python Enhancement Proposal”(Python增强提案).你可以在python.org上找到它们以及对应的索引目录. PEP在索引目录中按照数字编号排列,包括了元PEP(meta-PEP,讨论关于PEP的细节).与之对应的是技术PEP(techni

统计python文件中的代码,注释,空白对应的行数

其实代码和空白行很好统计,难点是注释行 python中的注释分为以#开头的单行注释 或者以'''开头以'''结尾 或以"""开头以"""结尾的文档注释,如: ''' hello world '''和 ''' hello world''' 思路是用is_comment记录是否存在多行注释,如果不存在,则判断当前行是否以'''开头,是则将is_comment设为True,否则进行空行.当前行注释以及代码行的判断,如果is_comment已经为True

python 正则表达式中反斜杠(\)的麻烦和陷阱

这里是一点小心得:由于下面两个原因,在正则表达式中使用反斜杠就会产生了一个双重转换的问题.(1).python自身处理字符串时,反斜杠是用于转义字符 (2).正则表达式也使用反斜杠来转义字符     要匹配字符串中1个反斜杠应该怎么写正则表达式?"\\",这样行吗?试试就知道了,re模块抛异常了,因为在正则表达式中,"\\"就是一个反斜杠,对于正则表达式解析器来说,是一个转义字符,但是后面啥也没有,自然就报错了,"\\\"三个肯定是不行的,试试四

python 正则表达式中反斜杠(\)的麻烦和陷阱 (转)

这里是一点小心得:由于下面两个原因,在正则表达式中使用反斜杠就会产生了一个双重转换的问题.(1).python自身处理字符串时,反斜杠是用于转义字符 (2).正则表达式也使用反斜杠来转义字符     要匹配字符串中1个反斜杠应该怎么写正则表达式?"\\",这样行吗?试试就知道了,re模块抛异常了,因为在正则表达式中,"\\"就是一个反斜杠,对于正则表达式解析器来说,是一个转义字符,但是后面啥也没有,自然就报错了,"\\\"三个肯定是不行的,试试四

python编程中的if __name__ == 'main与windows中使用多进程

if __name__ == 'main 一个python的文件有两种使用的方法,第一是直接作为程序执行,第二是import到其他的python程序中被调用(模块重用)执行. 因此if __name__ == 'main': 的作用就是控制这两种情况执行代码的过程, 在if __name__ == 'main': 下的代码只有在第一种情况下(即文件作为程序直接执行)才会被执行,而import到其他程序中是不会被执行的 第一种情况: def func(): print('second') prin

Python 面试中可能会被问到的30个问题

第一家公司问的题目 1 简述解释型和编译型编程语言? 解释型语言编写的程序不需要编译,在执行的时候,专门有一个解释器能够将VB语言翻译成机器语言,每个语句都是执行的时候才翻译.这样解释型语言每执行一次就要翻译一次,效率比较低. 用编译型语言写的程序执行之前,需要一个专门的编译过程,通过编译系统,把源高级程序编译成为机器语言文件,翻译只做了一次,运行时不需要翻译,所以编译型语言的程序执行效率高,但也不能一概而论, 部分解释型语言的解释器通过在运行时动态优化代码,甚至能够使解释型语言的性能超过编译型

Python程序中的进程操作-开启多进程(multiprocess.process)

目录 一.multiprocess模块 二.multiprocess.process模块 三.process模块介绍 3.1 方法介绍 3.2 属性介绍 3.3 在windows中使用process模块的注意事项 四.使用process模块创建进程 4.1 在Python中启动的第一个子进程 4.2 join方法 4.3 查看主进程和子进程的进程号 4.4 多个进程同时运行 4.5 多个进程同时运行,再谈join方法(1) 4.6 多个进程同时运行,再谈join方法(2) 4.7 通过继承Pro

Python - 基础中的基础

前景 Python可以应用于众多领域,如:数据分析.组件集成.网络服务.图像处理.数值计算和科学计算等众多领域.目前业内几乎所有大中型互联网企业都在使用Python,如:Youtube.Dropbox.BT.Quora(中国知乎).豆瓣.知乎.Google.Yahoo!.Facebook.NASA.百度.腾讯.汽车之家.美团等. 互联网公司广泛使用Python来做的事一般有:自动化运维.自动化测试.大数据分析.爬虫.Web 等. Python与其他语言 C和Python.java.C# C:代码