1

在以下链接http://en.literateprograms.org/Quicksort_%28Python%29中提出了以下声明。我们使用 pop 操作来删除我们选择的枢轴。这具有改变传递给排序函数的原始列表的不幸副作用。为什么它是一个不幸的副作用?即使我直接在下面调用 qsort 函数,我也会得到排序列表作为输出,因为我们有 return 语句。

from random import randrange       
def qsort1a(list):
    """
    Quicksort using list comprehensions and randomized pivot
    >>> qsort1a<<docstring test numeric input>>
    <<docstring test numeric output>>
    >>> qsort1a<<docstring test string input>>
    <<docstring test string output>>
    """
    def qsort(list):
        if list == []: 
            return []
        else:
            pivot = list.pop(randrange(len(list)))
            lesser = qsort([l for l in list if l < pivot])
            greater = qsort([l for l in list if l >= pivot])
            return lesser + [pivot] + greater
    return qsort(list[:])
4

4 回答 4

5

qsort1a实际上,通过将 your 定义为 inner 的包装器,您已经“解决了问题” qsort。您的包装器使用切片运算符复制原始列表:

return qsort(list[:])

如果删除复制操作,则使最后一行变为:

return qsort(list)

然后运行它,你可以看到为什么它是“坏的”:

>>> from qsort1a import qsort1a
>>> orig = [3, 17, 4, 0, 2]
>>> qsort1a(orig)
[0, 2, 3, 4, 17]
>>> orig
[3, 17, 4, 2]
>>> 

输出仍然排序,但原始列表orig已更改。

(另外,正如其他人所指出的,重用名称(list如局部变量)通常是不明智的,因为它使访问 Python 的内置list函数变得不必要地困难。)

于 2013-07-12T03:51:50.447 回答
4

这很糟糕,因为无论如何你都会得到一个新列表。为什么有两个相同列表的副本?如果您想在某处继续使用原始未排序列表怎么办。有返回值的函数可能不应该改变它们的参数。

编辑:我将提供一个示例,为什么变异参数会令人困惑。在 C++ 中。

添加琐碎的添加功能。

int add(int a, int b)
{
   a += b;
   return a;
}

int addBad(int &a, int &b)
{
   a += b;
   return a;
}

for(int i=0;i<10;++i)
{
   for(int j=0;j<10;++j)
   {
      cout << add(i,j) << endl;
   }
}

for(int i=0;i<10;++i)
{
   for(int j=0;j<10;++j)
   {
      cout << addBad(i,j) << endl;
   }
}

如果程序员不知道 和 中发生了什么,这两者看起来都非常add相似addBadadd和的实现addBad可以互换,代码仍然可以编译。Python 可能是类似的,因为通过引用传递似乎发生了很多并且没有明确声明它。

于 2013-07-12T03:46:32.143 回答
2

一切正常,因为您只需提供参数的副本。坏事是保持实现简单,使用pop和列表理解,你需要传递原始列表的几个副本。这不如就地排序那样有效。

顺便说一句,不要list用作变量名。

于 2013-07-12T03:49:50.043 回答
1

有时,您想对列表进行就地排序。有时,您需要列表的排序副本(例如,如果您还想保留原始未排序的顺序)。因此,Python 标准库允许您同时编写lst.sort()sorted(lst).

但在 Python 中,一个函数既改变其参数返回一个值是不常见的。更常见的约定是Command-Query Separation,其中 mutator 函数 return None。例如,在list类中,添加、删除或重新排序列表中的项目的appendclearextend、和方法都返回。removereversesortNone

pop方法是一个例外,实用性胜过纯度

于 2013-07-12T04:03:49.730 回答