python有列表构造函数吗?
python是否有像OCaml(python有列表构造函数吗?,python,list,Python,List,python是否有像OCaml(:)(或lisp)中的cons(或lisp)这样的列表构造函数,它接受head元素和tail列表,并返回一个新的列表head::tail 我搜索了python列表构造函数,最后找到了关于\uuuu init\uuuu的其他内容。见例 为了澄清,我要寻找的是Python中以下列表分解的相反形式: 这使得: >>>head 1 >>> tail [1, 2, 3, 5, 8, 13, 21, 34, 55] 我正在寻找一个列表构造
:
)(或lisp)中的cons
(或lisp)这样的列表构造函数,它接受head
元素和tail
列表,并返回一个新的列表head::tail
我搜索了python列表构造函数,最后找到了关于\uuuu init\uuuu
的其他内容。见例
为了澄清,我要寻找的是Python中以下列表分解的相反形式:
这使得:
>>>head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]
我正在寻找一个列表构造函数,例如cons
或:
这样
head :: tail => original list
Python列表是可变的,而OCaml列表具有不可变的值语义,但是如果
a
是一个项,b
是一个列表,则可以使用[a]+b
返回一个新列表,其中包含a
,后跟b
中的项,并且不修改a
或b
。不过,构建列表的一种更常见的模式是附加
或扩展
它。您可以使用列表连接
head = 1
tail = [2,3,4]
lst = [head] + tail # [1,2,3,4]
有些人建议你这样做:
a = 1
b = [2, 3, 4, 5]
c = [a] + b
如果b
类型为list
,则该选项将起作用。但是,您经常会发现自己使用的对象是列表或元组或(在此处插入您最喜欢的iterable对象)。在这种情况下,您可能更值得这样做:
a = 1
b = (2, 3, 4, 5)
c = [a]
c.extend(b)
这使得整个事情对b
的类型不可知(这允许您的代码更“ducky”,这可能有点好)
当然,还有其他选择。例如,您可以选择访问
itertools
:
import itertools
a = 1
b = [2, 3, 4, 5]
lazy_c = itertools.chain([a], b)
同样,我们不关心iterable
b
是什么类型的,这是一个好处,而且我们还得到了懒洋洋地迭代的一个附带好处——我们不会创建新的列表或元组。我们将创建一个对象,当您对它进行迭代时,它将产生相同的结果。这可以节省内存(有时还可以节省CPU的周期),但如果b
也是一种类似生成器的对象,同时在其他地方进行迭代(这不是经常发生的),也可能会产生意想不到的后果。回答您的问题,在所谓的“函数式”语言(lisp、OCaml、Haskell等)中,没有直接的等价物
这是因为在编程语言中有两个相互竞争的模型来表示元素列表
链表
你似乎熟悉的一个叫做链表
链表由cons单元格组成,每个单元格包含两个引用:
- 第一个指向列表中的一个元素,称为head
- 另一个指向列表中的下一个cons单元格,是尾部
l = [1, 2, 3]
l <-- your variable
| ___ ___ ___ ___ ___ ___ ___ ___ ___
|-> | | | | | | | | | |
| 1 | 2 | 3 | | | | | | |
|___|___|___|___|___|___|___|___|___|
每当您创建一个列表时,Python都会给它分配一个小范围的内存来存储元素,并留出一点额外的空间,以备以后添加元素时使用。要存储它,只需存储对第一个元素和内存范围大小的引用,如下所示:
l = [1, 2, 3]
l <-- your variable
| ___ ___ ___ ___ ___ ___ ___ ___ ___
|-> | | | | | | | | | |
| 1 | 2 | 3 | | | | | | |
|___|___|___|___|___|___|___|___|___|
结果如下:
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|
现在,假设您忘记了首字母0,现在希望将其添加到前面。您可以很好地使用insert方法(insert位置为0):
但是列表的开头没有空格!Python别无选择,只能将每个元素都复制到右边的位置:
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|
| | |__ |___
| |___ | | First, Python has to copy the four elements
|___ | | | one space to the right
___ _\/ _\/ \/_ _\/ ___ ___ ___ ___
| | | | | | | | | |
| | 1 | 2 | 3 | 4 | | | | |
|___|___|___|___|___|___|___|___|___|
Only then can it insert the 0 at the beginning
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 0 | 1 | 2 | 3 | | | | | |
|___|___|___|___|___|___|___|___|___|
对于这样一个小的数组来说,这似乎不算什么,但想象一下您的数组要大得多,并且您多次重复此操作:您将花费大量时间构建列表
这就是为什么在使用数组作为列表的语言(如Python)中找不到列表构造函数的原因
进一步潜水:为什么两种不同的模式?
您现在可能想知道为什么不同的语言会喜欢不同的列表模型,以及这两种模型中是否有一种更优越
这是因为这两种数据结构在不同的上下文中具有不同的性能。两个例子:
访问中间元素
假设您想要获取列表的第五个元素
在链接列表中,您需要获得:
- 第一个囚室
- 然后这个单元格的尾部得到第二个元素
- 然后这个单元格的尾部得到第三个元素
- 然后这个单元格的尾部得到第四个元素
- 最后是这个单元格的尾部,得到第五个元素
假设你现在想在中间插入一个元素。
使用链接列表:- 找到与插入点前最后一个元素对应的cons单元格。
___ ___ ___ ___ ___ ___ ___ ___ ___ | | | | | | | | | | | 1 | 2 | 3 | 4 | | | | | | |___|___|___|___|___|___|___|___|___| | | |__ |___ | |___ | | First, Python has to copy the four elements |___ | | | one space to the right ___ _\/ _\/ \/_ _\/ ___ ___ ___ ___ | | | | | | | | | | | | 1 | 2 | 3 | 4 | | | | | |___|___|___|___|___|___|___|___|___| Only then can it insert the 0 at the beginning ___ ___ ___ ___ ___ ___ ___ ___ ___ | | | | | | | | | | | 0 | 1 | 2 | 3 | | | | | | |___|___|___|___|___|___|___|___|___|