雪花飘落

sorted函数中的key

sorted函数有三个参数:iterable、key、reverse。

其中,iterable为一个可迭代的对象,reverse表示是否对排序结果进行反转,而key稍微复杂一点,主要是用来对需要比较的元素进行处理,可以是一个函数,也可以是一个类,也可以是其他的处理方法。

key的工作原理

key的大概工作流程就是首先对序列中所有的元素逐一调用方法、函数或者类进行处理,如果是方法,一般是返回一个固定的值这个值一般是内置的类型。如果是类,则是直接调用构造函数,生成一个对象,所以作为key的类必须有一个构造函数,这个函数仅支持一个参数(除self外)用来接收序列中的元素。

内建函数\方法

先来看使用内建的函数或者方法处理的效果:

ls = ["a", "b", "c", "D", "E"]
# 直接排序,结果为['D', 'E', 'a', 'b', 'c']
print(sorted(ls))
# 使用lower,将所有元素转化为小写字母再排序['a', 'b', 'c', 'D', 'E']
# 因为lower是字符串的方法,所以这里要加上调用方为字符串类型
print(sorted(ls, key=str.lower))

自定义函数

既然可以使用内建的函数或者方法,那么当然也可以自定义函数,执行排序时,会对序列中的每一个元素依次调用我们指定的函数,然后把返回值拿来做比较。

# 例如我们想把列表中的数字按照个位的大小进行排序,那么就可以定义一个函数,返回一个整数的个位数
def gewei(num: int) -> int:
    return num % 10


ls = [991, 86, 3]
# 结果为[991, 3, 86]
print(sorted(ls, key=gewei))
# 当然,我们也可以写lamda表达式(匿名函数),结果是一样的
print(sorted(ls, key=lambda num: num % 10))

前面说到了,如果传入类作为key的参数,那么会依次将序列中的元素作为类构造函数的参数,然后将生成的对象作比较。

这里要提一点,对象作比较,实际上是调用类的__lt__或者__gt__方法,因此,类必须实现其中一个方法。

关于__lt__和__gt__方法

__lt__、__gt__分别表示:小于、大于,对应的操作符为:'<'、'>'。

1.当自定义类中两个方法都定义了时,'<'和'>'分别调用__lt__和__gt__方法;

2.当自定义类中定义了__lt__方法,未定义__gt__方法时,进行”>”比较也是调用__lt__方法,只是对调用值求反。

class Stu:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # __lt__方法有两个参数,分别表示自身对象和其它对象,这种格式是固定的,__gt__也是一样
    # 这里我们定义,两个Stu对象比较时,age属性较小的一方更小
    def __lt__(self, other):
        return self.age < other.age


s1 = Stu("小明", 10)
s2 = Stu("小红", 12)
# 结果为True,如果类里没有实现__lt__或者__gt__方法,那这里就会报错
print(s1 < s2)

类作为key参数

上面定义的类构造函数需要接受两个参数,name和age,所以这样的类是不能作为key的参数值的,因为key是将序列中的每一个元素依次传入,所以类构造函数能且只能接受一个参数:

class Stu:
    def __init__(self, age):
        self.age = age

    def __lt__(self, other):
        # 这里我故意反着来,年龄比较大的一方反而更小
        return self.age > other.age


ls = [10, 20, 11, 4, 9, 23]
# 虽然默认为升序,但是比较规则里是年龄更大的对象更小,所以年龄大的会排前面
# 结果为[23, 20, 11, 10, 9, 4]
print(sorted(ls, key=Stu))

 

posted @ 2022-10-06 18:02  haruyuki  阅读(1254)  评论(0编辑  收藏  举报