在获得更多 Python 经验后重新审视这个问题时,我想到了一个解决方案,但它违反了我当时要求的不定义函数的属性。
def make_list_containing(*args):
return list(args)
然后make_list_containing(3)
或make_list_containing('foo')
按预期行事(与list
构造函数相反,您必须改变直觉来学习如何期望它起作用)。
令我惊讶的是,list
作为构造函数是“转换为list
类型”而不是“放入list
对象实例”的同义词。
我可以看到构造函数的多态行为在单例也是可迭代的情况下可能是模棱两可的,比如字符串。但是,为什么不支持不可迭代单例的“放入列表”行为?
另一件事是,至少对我而言,我所描述的方法似乎更一致,更符合最小惊讶。
make_list_containing
你知道你总是会得到一个列表,它会包含传入的元素。只要你以你想要的格式传入它们,那么这正是你会得到的。考虑:
In [34]: make_list_containing(*'foo')
Out[34]: ['f', 'o', 'o']
In [35]: make_list_containing('foo')
Out[35]: ['foo']
或者
In [40]: make_list_containing(*enumerate(range(3)))
Out[40]: [(0, 0), (1, 1), (2, 2)]
In [41]: make_list_containing(enumerate(range(3)))
Out[41]: [<enumerate at 0x7f61a7f0fd70>]
现在这对我来说似乎更直观。预先设置这*
正是我应该如何“去迭代”作为参数的东西中的项目。如果我不特意选择它,那么我必须将其'foo'
视为单例,并计划在函数调用内部自己处理其元素或可迭代性。
在这次谈话中令人沮丧的一件事是,仅仅因为 Python 的这种约定是老人们似乎将其与意义混为一谈,这并不奇怪。但这是对惊喜的狭义定义。是的,当我启动翻译时,我不再“惊讶”list('foo')
给我['f', 'o', 'o']
。但我仍然感到惊讶的是,对于构造函数来说,语言的接口选择与list
. 这让我感到惊讶,因为它似乎有更多的设计弱点而不是优势,而且最初用来证明它的理由是对语法的一些固定,而不是思想的清晰。
在这一点上,它偏离了意见区太远了,我显然同意这样一个事实,即由于压倒性的历史势头,这在 Python 中不会改变。但是我的问题的精神仍然是关于这个非常合理的观点。这不是“懒惰”或“只需编写一个包装函数并继续前进”的问题,因为大多数评论似乎都希望它是。