Python 中是否有 sorted() 的神奇方法?

is there a magic method for sorted() in Python?

我知道 python 中有魔法方法可以被 类 覆盖,以控制某些内置函数处理这些 类 成员的方式。例如,len()str() 的行为可以通过魔术方法 __len__()__str__():

覆盖
class EmptySet(object):
    def __len__(self):
        return 0

    def __str__(self):
        return '[]'

>>> e = EmptySet()
>>> str(e)
[]

>>> len(e)
0

还有 __cmp__()__ge__()__le__() 等方法来控制如何比较这些对象以及如何按 list.sort() 对它们的列表进行排序.我的问题不是关于自定义列表中对象的顺序,而是关于对对象本身进行排序。假设集合不为空,我想使用 sorted() 对其进行排序:

class SetOfTwo(object):
    def __init__(self, a , b):
        el_0 = a
        el_1 = b

    def __len__(self):
        return 2

    def __str__(self):
        return '[{}, {}]'.format(el_0, el_1)

有没有我可以实现的神奇方法 sorted() 翻转不按顺序排列的元素?我正在描绘以下行为:

>>> s = SetOfTwo(2, 1)
>>> str(s)
[2, 1]

>>> t = sorted(s)
>>> str(t)
[1, 2]

>>> type(t)
>>> SetOfTwo

您绝对应该阅读 the official documentation 如何模拟容器类型。基本上,一个 class 应该作为容器(列表、字典等)工作需要实现方法来设置或获取成员 __getitem__()__setitem__() 并迭代项目 __iter__() 和获取项目的数量 - 方法 __len__()这是最低要求。但是你也可以添加删除项目等操作的能力。

sorted() built-in 函数的行为是迭代容器的元素并使用您提到的方法比较它们 __cmp__(), __ge__(), __le__() 应该为项目而不是容器定义为你已经知道了。然后创建一个新的 list 实例,其中的项目已排序,并且这个新实例是 returned。然后您可以将它传递给自定义容器的构造函数,或者您可以使用自定义函数包装 sorted(),这将 return 所需的 class 实例。

正如某些人在评论中所说,集合是无序的,但我认为您的问题并不是关于集合的。

Python 使用您提到的数据模型方法,gelecmp 来确定 class 在调用 sorted() 时的行为。你可以在这里看到我是如何尝试调用它的,但是 Python 反对并要求我实现 <.

>>> class a(object):
...   pass
...
>>> b = a()
>>> c = a()
>>> d = [b, c]
>>> sorted(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'a' and 'a'

希望这对您有所帮助。另外,正如其他人所说,将 collections.abc 中的某些内容子 class 是个好主意。我阅读了 effective python 中的第 28 条,其中讨论了这个问题以获得一个好主意。

len()str() 是将对象作为参数的函数,return 是整数(分别为字符串)。该对象可以通过 __len__()__str__() 魔术方法个性化计算 len 或生成字符串的方式。

类似地,sorted() 是一个接受对象列表(或任何可迭代对象)和 returns 排序对象列表的函数 。这些对象可以通过 __lt__() 魔术方法个性化比较它们的方式。

当我们将 `sorted(my_list) 视为 "sorts the list" 而不是 "sorts the elements of the list".

的函数时,会出现一些混淆

您不想对您的对象进行排序(即制作一个有序的对象列表),而只是对一些数据的内部表示进行排序。因此,您需要在对象上使用一个实例方法来更新该内部表示。你可以随意命名,.sort()如果你喜欢,但是你必须在你的一个对象上调用它,它不会参与比较对象。