python - 为什么不能重设字典?
问题描述
我编写了一个函数来递归地列出所有文件和目录。
import os
def walk_dir(path,dir_list=[],file_list=[]):
for fname in os.listdir(path):
fullname = os.path.join(path, fname)
if os.path.isdir(fullname) :
dir_list.append(fullname)
walk_dir(fullname,dir_list,file_list)
elif os.path.isfile(fullname) :
file_list.append(fullname)
return {'dir':dir_list,'file':file_list}
它返回一个字典。
我创建了一个目标目录来测试我的代码。
mkdir -p /tmp/test
cd /tmp/test
mkdir -p test{1..3}
cd test1
touch /test1/test1{1..3}
cd ../test2
touch /test2/test2{1..2}
这是我要尝试的目标目录:
tree /tmp/test
/tmp/test
├── test1
│ ├── test11
│ ├── test12
│ └── test13
├── test2
│ ├── test21
│ └── test22
├── test3
获取所有目录和文件/tmp/test
。
x = walk_dir('/tmp/test')
x['dir']
['/tmp/test/test1', '/tmp/test/test3', '/tmp/test/test2']
现在将 x 重置为{}
--a 字典不包含任何内容。
x = {}
x
{}
x['dir']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'dir'
dir_list
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'dir_list' is not defined
也许每个变量都被初始化为无。
第二次获取文件和目录:
x = walk_dir('/tmp/test')
x['dir']
['/tmp/test/test1', '/tmp/test/test3', '/tmp/test/test2', '/tmp/test/test1', '/tmp/test/test3', '/tmp/test/test2']
我已重置x
为{}
,为什么 x['dir'] 包含 6 个目录而不是 3 个目录?
解决方案
这是 Python 的陷阱之一。
空列表的默认参数是在函数定义中创建的。它在函数调用之间仍然存在。
你可以在这里看到它的演示。test_func 是一个具有列表默认参数的函数。然后列表被修改,修改存在并且每次函数运行时都会改变。
>>> def test_func(param=[]):
... param.append(1)
... print(param)
...
>>> test_func()
[1]
>>> test_func()
[1, 1]
>>> test_func()
[1, 1, 1]
>>> test_func()
[1, 1, 1, 1]
>>> test_func()
[1, 1, 1, 1, 1]
>>> test_func()
[1, 1, 1, 1, 1, 1]
如果您查看输出,您会看到重复项。每条路径存在两次。如果你再次运行它,它应该有三个重复,依此类推。这仅适用于可变类型。所以列表和字典之类的东西会表现出这种行为。如果您不打算使用此行为,请避免将它们用作默认参数。
而是使用将默认参数设置为 None 并在函数体内检查它。
>>> def test_func2(param=None):
... if param is None:
... param = []
... param.append(1)
... print(param)
...
>>> test_func2()
[1]
>>> test_func2()
[1]
>>> test_func2()
[1]
推荐阅读
- angular - 使用符号链接时,Windows 上的 Angular ng serve (angular-cli) 找不到资产文件
- angular - 角卡中的垂直截面
- fonts - 命令提示符中的字符 '!1' 和 '!2'
- c# - 谷歌对 /token 的期望是什么?
- javascript - HTML Canvas javascript 在 Z 轴上移动对象
- java - 与 TextWatcher 相关的代码仅适用于一个 EditView
- python - 从对列表中查找所有最大有向连接组
- r - 拆分列表中的项目 - R
- c++ - 是否可以在 C++ 中使用 Apache Ignite 设置到期时间?
- python - 用不同的数据框替换列