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

依然范特西╮ 提交于 2020-07-21 04:07:05

问题


I understand that there are magic methods in python that can be overwritten by classes to control the way certain built in functions treat the members of these classes. For example, the behavior of len() and str() can be overwritten via magic methods __len__() and __str__():

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

    def __str__(self):
        return '[]'

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

>>> len(e)
0

There are also __cmp__() and __ge__(), __le__() etc methods to control how these objects can be compared and how a list of them should be ordered by list.sort(). My question is not about customizing the ordering of objects in a list but about sorting the object itself. Suppose the set weren't empty and I want to use sorted() to sort it:

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)

Is there a magic method I can implement to have sorted() flip the elements if they aren't in order? I'm picturing the following behavior:

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

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

>>> type(t)
>>> SetOfTwo

回答1:


You should definitely read the official documentation of how to emulate container types. Basically a class supposed to work as a container (list, dict etc.) needs to implement methods to set or get members __getitem__(), __setitem__() and iterate over items __iter__() and to get the number of items - method __len__(). This is the minimum. But you can also add the ability to delete items and other operations.

The behaviour of sorted() built-in function is to iterate over elements of your container and compare them using methods you mentioned __cmp__(), __ge__(), __le__() which should be defined for items and not the container as you know already. Then a new list instance is created with items sorted and this new instance is returned. You can pass it to the constructor of your custom container then or you can wriap sorted() with a custom function which will return the desired class instance.




回答2:


As some have said in the comments, sets are unordered but I don't think your question is really about sets.

Python uses the data model methods you mentioned, ge, le, and cmp to determine how a class behaves when sorted() is called on it. You can see how I try to call it here, but Python objects and asks me to implement <.

>>> 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'

Hope this helps. Aslo, as other people said, it's a good idea to subclass something in collections.abc. I'd read Item 28 in effective python that talks about this to get a good idea.




回答3:


len() and str() are functions who take an object as parameter and return an integer (resp. string). The object can personalize the way the len is calculated, or the string is generated, via the __len__() and __str__() magic methods.

Similarly, sorted() is a function that takes a list (or any iterable) of objects and returns a list of the sorted objects. The objects can personalize the way they get compared through the __lt__() magic method.

Some confusion arises when we think of `sorted(my_list) as a function that "sorts the list", rather than "sorts the elements of the list".

You don't want to sort your objects (i.e. make an ordered list of objects), but only sort some data in their internal representation. So you need an instance method on your object that will update that internal representation. You can name it as you wish, .sort() if you'd like, but you will have to call it on your one object, and it will not be involved in comparing objects.



来源:https://stackoverflow.com/questions/48868228/is-there-a-magic-method-for-sorted-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!