How can I get 2.x-like sorting behaviour in Python 3.x?

后端 未结 10 889
陌清茗
陌清茗 2020-11-27 06:50

I\'m trying to replicate (and if possible improve on) Python 2.x\'s sorting behaviour in 3.x, so that mutually orderable types like int, float etc.

10条回答
  •  天命终不由人
    2020-11-27 07:29

    I tried to implement the Python 2 sorting c code in python 3 as faithfully as possible.

    Use it like so: mydata.sort(key=py2key()) or mydata.sort(key=py2key(lambda x: mykeyfunc))

    def default_3way_compare(v, w):  # Yes, this is how Python 2 sorted things :)
        tv, tw = type(v), type(w)
        if tv is tw:
            return -1 if id(v) < id(w) else (1 if id(v) > id(w) else 0)
        if v is None:
            return -1
        if w is None:
            return 1
        if isinstance(v, (int, float)):
            vname = ''
        else:
            vname = type(v).__name__
        if isinstance(w, (int, float)):
            wname = ''
        else:
            wname = type(w).__name__
        if vname < wname:
            return -1
        if vname > wname:
            return 1
        return -1 if id(type(v)) < id(type(w)) else 1
    
    def py2key(func=None):  # based on cmp_to_key
        class K(object):
            __slots__ = ['obj']
            __hash__ = None
    
            def __init__(self, obj):
                self.obj = func(obj) if func else obj
    
            def __lt__(self, other):
                try:
                    return self.obj < other.obj
                except TypeError:
                    return default_3way_compare(self.obj, other.obj) < 0
    
            def __gt__(self, other):
                try:
                    return self.obj > other.obj
                except TypeError:
                    return default_3way_compare(self.obj, other.obj) > 0
    
            def __eq__(self, other):
                try:
                    return self.obj == other.obj
                except TypeError:
                    return default_3way_compare(self.obj, other.obj) == 0
    
            def __le__(self, other):
                try:
                    return self.obj <= other.obj
                except TypeError:
                    return default_3way_compare(self.obj, other.obj) <= 0
    
            def __ge__(self, other):
                try:
                    return self.obj >= other.obj
                except TypeError:
                    return default_3way_compare(self.obj, other.obj) >= 0
        return K
    

提交回复
热议问题