在python或coffeescript中,为什么list.append不返回列表本身?如果是这样,递归可以简单得多

在python或coffeescript中,为什么list.append不返回列表本身?如果是这样,递归可以简单得多,python,functional-programming,coffeescript,Python,Functional Programming,Coffeescript,如果insert()返回列表本身,请考虑以下代码 def sieve(l): if not len(l): return [] return sieve(filter(lambda x: x%l[0] != 0, l)).insert(0, l[0]) 现在,我们必须依靠helper函数在插入后返回列表 def cons(a, l): l.insert(0, a) return l def sieve(l): if not len(l): return [

如果insert()返回列表本身,请考虑以下代码

def sieve(l):
  if not len(l):
    return []
  return sieve(filter(lambda x: x%l[0] != 0, l)).insert(0, l[0])
现在,我们必须依靠helper函数在插入后返回列表

def cons(a, l):
  l.insert(0, a)
  return l

def sieve(l):
  if not len(l):
    return []
  return cons(l[0], sieve(filter(lambda x:x%l[0] != 0, l)))

可变/不可变对象的点是完全有效的


然而,对于可变的列表,IMHO,append()API可以采取更多步骤来返回列表本身,而不是不返回任何内容。Java StringBuilder就是一个很好的例子。我可以递归地在stringbuilder对象上进行链式追加……但愿我们在这里也能做到这一点。

在Python中,让初学者了解哪些对象是“不可变”且不能更改的,哪些对象是“可变”且可以更改的是一件大事,在后一种情况下,对对象的每个引用都会看到相同的更改。这似乎真的让新来者感到困惑。“我天真地调用了我编写的这个函数,突然我的列表副本也改变了!”

因此Python有一个约定:不可变对象,当您要求它们进行调整时,返回新创建的对象作为答案-因此:

a = 'my string'
b = a.replace('y', 'e')
使
b
获取一个全新的字符串,而
a
保留其原始值。显然,这样的方法必须返回一个值,因为通过检查原始的、不可变的对象本身,您永远看不到更改


但是当你要求一个可变对象改变它自己时,它不会返回它自己,因为它不需要——你只需再次查看原始对象就可以看到改变!在Python中,这是一个关键的语义信号:如果像
append()
这样的方法没有返回新对象,那么您只需查看旧对象就可以看到更改,引用旧对象的其他人也可以看到更改。

为什么不创建一个引用呢?我认为这也会使代码更具可读性。

因为您询问了CoffeeScript

push
方法在适当的位置修改数组。它不会返回新修改的数组,而是返回刚才添加的值。当然,这是不直观的,但它可能是有用的。例如,你可以写这样的东西

getNewValue -> cache.push fetchValue()
它在一行中获取一个值,将其添加到
缓存
,并从
getNewValue
返回该值

另一方面,
concat
方法不修改原始数组,而是返回修改后的副本。它应该用于连接两个数组,但非数组值将被强制,因此如果需要,可以将其用作
push
替换:

arr = [1, 2, 3]
arr = arr.concat 4
console.log arr  # [1, 2, 3, 4]

关于JavaScript数组方法的完整文档是可用的。

我想如果有人认为他们可以使用
b=a.append(0)
,而没有意识到现在
a就是b
,可能会引起很多混乱。您的列表对象上必须已经有一个引用才能调用绑定方法
。append
,这样您就不需要将对它的另一个引用返回给您。我不知道这与CoffeeScriptgood Response有什么关系。使用
x=[1,2]
,比较并对比
x.sort()
sorted(x)
,注意
sorted(x)==x和sorted(x)不是x