鱼C论坛

 找回密码
 立即注册
查看: 1331|回复: 3

[已解决]关于递归问题以及函数内部修改外部变量的疑问

[复制链接]
发表于 2018-7-25 11:57:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1.为什么代码1可以内部修改result变量?
2.若result放到内部则结果显示为[5],会每次将result重置
3.代码2刚好相反,放在外部反而提醒未定义。而放在内部为什么不会每次运行都将result重置呢?
4.是因为列表为可变变量吗,但是还是不太懂,麻烦高手详细指点


代码思路为将一串数字转化为列表,如12345转化为[1,2,3,4,5]
  1. result = []
  2. def get_digits(n):
  3.     if n > 0:
  4.        get_digits(n // 10)
  5.        result.append(n % 10)
  6.     return result

  7. print(get_digits(23546))
  8. print(result)
复制代码

  1. def get_digits(n):
  2.     result = ''
  3.     if n:
  4.         result = get_digits(n // 10)
  5.         result += str(n % 10)
  6.     return list(result)

  7. print(get_digits(12345))
复制代码


感谢各位大佬相助,本学渣感激不尽!
最佳答案
2018-7-25 13:48:09
1. result 在 get_digits(n) 内部是没有被定义的。如果函数在函数体范围内找不到相关的变量(先不要管是局部还是全局变量),就会往那一行代码之前的代码搜索。result.append() 在第 5 行,往 4 - 1 行搜索,结果就在第 1 行找到了,所以第 5 行的 result 会对应到函数体外的变量。但真正调用 get_digits() 是在第 8 行,所以应该是往 7 - 1 行搜索。如果变量的定义在被调用的时候没有被定义,就会报错。自己尝试把 result 还有 def 的位置换到不同的地方。

2. 没错,如果 result = [] 放到函数内部的话,就是说函数每被调用一次,就会制造一个空列表。函数把结果返回之后,就会把函数内部变量所占的内存给清空。结果就是每次会重置。

3. 注意,这个函数是递归呼叫。看看第 4 行 result = get_digits(n//10),那么 get_digits(n//10) 就调用 get_digits(n) ,而里边又要找 result = get_digits() ... 就是一直找不到就对了,所以不能放在函数外部。

我们剖析一下您的代码(我简化一下):
get(12345)  ## 在第 8 行呼叫函数
r = []
if 12345: ## n != 0 == True
r = get(1234)
r = r + '5'

呼叫 get(1234) 变成:
r = []
if 12345:
r = []
if 1234:
r = r + '4'
r = r + '5'
...

结果会是 result 被初始化了好几次,最后 []+'1' + '2'+...+'5'

4. 最大的差别在于有没有赋值。代码一:get_digits(n // 10) 代码二:result = get_digits(n //10)。代码一因为没有 result =,所以不会一直去找 result 在哪里,只是知道 result 已经被定义,最后把运算结果附在一起 (append >> appendix >> 附录)。代码二则一直强调函数要改变 result 的值。

如果 result = [] 在代码一的函数内部,结果并不会是全空,最后一个打印出来的结果是有值的。效率上来说,代码一比较好,干净且省事。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-7-25 13:03:37 | 显示全部楼层
函数外的可变对象可以在函数内被修改。
函数外不可变对象可以被引用,但不能修改。
代码二企图修改result,而函数内没有事先赋值的话,会报错。
代码二每次递归的时候result每次是被重置的,但是递归返回的时候,result一层层进行了累加,你debug下可以看得很清楚。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-7-25 13:48:09 | 显示全部楼层    本楼为最佳答案   
1. result 在 get_digits(n) 内部是没有被定义的。如果函数在函数体范围内找不到相关的变量(先不要管是局部还是全局变量),就会往那一行代码之前的代码搜索。result.append() 在第 5 行,往 4 - 1 行搜索,结果就在第 1 行找到了,所以第 5 行的 result 会对应到函数体外的变量。但真正调用 get_digits() 是在第 8 行,所以应该是往 7 - 1 行搜索。如果变量的定义在被调用的时候没有被定义,就会报错。自己尝试把 result 还有 def 的位置换到不同的地方。

2. 没错,如果 result = [] 放到函数内部的话,就是说函数每被调用一次,就会制造一个空列表。函数把结果返回之后,就会把函数内部变量所占的内存给清空。结果就是每次会重置。

3. 注意,这个函数是递归呼叫。看看第 4 行 result = get_digits(n//10),那么 get_digits(n//10) 就调用 get_digits(n) ,而里边又要找 result = get_digits() ... 就是一直找不到就对了,所以不能放在函数外部。

我们剖析一下您的代码(我简化一下):
get(12345)  ## 在第 8 行呼叫函数
r = []
if 12345: ## n != 0 == True
r = get(1234)
r = r + '5'

呼叫 get(1234) 变成:
r = []
if 12345:
r = []
if 1234:
r = r + '4'
r = r + '5'
...

结果会是 result 被初始化了好几次,最后 []+'1' + '2'+...+'5'

4. 最大的差别在于有没有赋值。代码一:get_digits(n // 10) 代码二:result = get_digits(n //10)。代码一因为没有 result =,所以不会一直去找 result 在哪里,只是知道 result 已经被定义,最后把运算结果附在一起 (append >> appendix >> 附录)。代码二则一直强调函数要改变 result 的值。

如果 result = [] 在代码一的函数内部,结果并不会是全空,最后一个打印出来的结果是有值的。效率上来说,代码一比较好,干净且省事。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-7-25 14:56:49 | 显示全部楼层
凌九霄 发表于 2018-7-25 13:03
函数外的可变对象可以在函数内被修改。
函数外不可变对象可以被引用,但不能修改。
代码二企图修改result ...

十分感谢您的帮助!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-11 20:44

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表