学了 1 年 Python ,今天看了段代码觉得白学了,求教一下大家

2021-03-04 15:03:43 +08:00
 zhoudaiyu

把代码精简了一下

我本以为输出结果会是个[[],[]],输出结果是个列表嵌套了两个列表,每个列表里又嵌套了 2 个列表...

猜测是个递归,debug 一下确实是这样的

有几个问题:

1 、这个为啥是个递归?
2 、这个递归为什么没有爆栈?
3 、修改了一下代码,为什么返回了(True, True)?

4380 次点击
所在节点    Python
20 条回复
chaosgoo
2021-03-04 15:11:12 +08:00
1.root 里面放了两个 root 的引用
2.root 里面只是存了两个地址而已
3.自己和自己比较当然是 True
THESDZ
2021-03-04 15:14:03 +08:00
实参,形参
zhoudaiyu
2021-03-04 15:15:27 +08:00
@zhoudaiyu

大家忽略最后一个问题,脑残了
aijam
2021-03-04 15:16:16 +08:00
相当于:
root = []
root.append(root)
root.append(root)
vicalloy
2021-03-04 15:17:22 +08:00
同楼上,就是一个递推的引用,换成 dict 是不是就好理解多了。
>>> o = {}
>>> o['o'] = o
>>> o
{'o': {...}}
Vegetable
2021-03-04 15:17:34 +08:00
Circular reference detected

给你化简一下吧
root = []
root.append(root)
aijam
2021-03-04 15:17:49 +08:00
先理解下面什么意思,也就好理解了
root = []
root.append(root)
nznd
2021-03-04 15:22:27 +08:00
>>> root=[]
>>> id(root)
2296081934592
>>> id(root[:])
2296081935040
>>> root[:]=[root,root]
>>> id(root)
2296081934592
>>> id(root[:])
2296081935040
>>> id(root[0])
2296081934592
>>> id(root[1])
2296081934592
简单来说 就是 root[0] 和 root[1] 都指向了 root,root[:]是 root 的一个指针(类似的概念 忘了叫啥了,刷 leetcode 可以用这个装作是原地算法(直接改这个值
acmore
2021-03-04 15:33:35 +08:00
魔法就是自指广义表:
root = []
root.append(root)

另外基本上所有语言都可以这么玩,不只是 Python
RockShake
2021-03-04 15:35:41 +08:00
自己引用了自己,死循环,print 无法打印出所有
SystemLight
2021-03-04 15:45:25 +08:00
root[:]=[1,2]和 root=[1,2]两种写法有啥区别
karloku
2021-03-04 15:48:19 +08:00
1.
上面都回答了

2.
爆栈对应于堆栈. 变量引用不会建立堆栈, 自然没有爆栈问题.
如果你准备用递归的函数来深层处理这个变量, 每次函数调用都会建立堆栈, 那基本就要爆了.
karatsuba
2021-03-04 18:21:28 +08:00
这个不限于[], 即 root=[1], root=root.append(root),也会是[1, [...]]
Jirajine
2021-03-04 18:29:31 +08:00
一切皆对象(的引用)
因而所有变量都是引用类型(值类型可以看作是一种 inline 优化,因而可以看作引用类型)
lizytalk
2021-03-04 18:47:49 +08:00
你想说 root[0] == root 和 root[0] is root 都是 True ? root=root 和 root is root 是 True 没什么可说的吧
dayeye2006199
2021-03-05 05:33:50 +08:00
这个写法有什么实际用途吗?想学习一下魔法
SjwNo1
2021-03-05 09:29:51 +08:00
可变类型 地址引用
no1xsyzy
2021-03-05 10:19:45 +08:00
数据自指不叫递归,因为它不会执行。

@SystemLight 一个修改 list 内容,一个修改 locals() 绑定。
cassidyhere
2021-03-05 10:35:32 +08:00
标准库 functools.lru_cache 把它当双向链表用
摘部分代码:
PREV, NEXT, KEY, RESULT = 0, 1, 2, 3 # names for the link fields
root = [] # root of the circular doubly linked list
root[:] = [root, root, None, None] # initialize by pointing to self

# Use the old root to store the new key and result.
oldroot = root
oldroot[KEY] = key
oldroot[RESULT] = result
# Empty the oldest link and make it the new root.
# Keep a reference to the old key and old result to
# prevent their ref counts from going to zero during the
# update. That will prevent potentially arbitrary object
# clean-up code (i.e. __del__) from running while we're
# still adjusting the links.
root = oldroot[NEXT]
oldkey = root[KEY]
oldresult = root[RESULT]
root[KEY] = root[RESULT] = None
lithbitren
2021-03-06 01:14:51 +08:00
只要引用名归零或者作用域销毁,循环引用也是可以被 GC 的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/758444

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX