领先的免费Web技术教程,涵盖HTML到ASP.NET

网站首页 > 知识剖析 正文

python基础包functools的cmp_to_key, 比较方法和关键方法-亢保星

nixiaole 2024-12-03 00:02:47 知识剖析 17 ℃
#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
## 一 functools介绍
1、functools 模块可以说主要是为 函数式编程而设计,用于增强函数功能。
2、functools模块用以 为可调用对象(callable objects)定义高阶函数或操作。
3、functools下面包括:partial
                    update_wrapper __doc__
                    wraps
                    reduce   map reduce
                    cmp_to_key
                    lru_cache
                    singledispatch
## 二 cmp_to_key : 字面意思:cmp是比较的意思,key是关键字的意思。
## 三 应用场景,是为了兼容以前的版本
## 四 方法功能:
Transform an old-style comparison function to a key function
将老旧风格的对比方法,转变为关键字风格
. Used with tools that accept key functions
(such as sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()).
这个cmp_to_key方法,服务于的方法有sorted方法,min()方法,max()方法等,这些方法都会接受一个关键方法。
"""
"""
This function is primarily used as a transition tool for programs 
being converted from Python 2 which supported the use of comparison functions.
1. python2支持比较方法,现在不支持了。
2. 需要将对比方法转化为关键方法。
2. cmp_to_key 就是将对比方法转为关键方法。
"""
"""
A comparison function is any callable that accept two arguments, compares them, and
对比方法接受两个参数,然后对比这两个参数
returns a negative number for less-than, zero for equality, or a positive number for greater-than. 
返回负值代表小于,0代表等于,正值,代表大于。
"""
"""
A key function is a callable that accepts one argument 
and returns another value to be used as the sort key.
关键方法,接受一个参数,然后返回另外一个参数进行对比。
"""
"""
总结:对比方法接受两个参数,返回正负零。关键方法接受一个参数,返回一个数据用于对比。
我们需要研究python中的排序。
"""
iterable=["张山","李四","九日","利达","lili"]
from functools import cmp_to_key
import locale
a = sorted(iterable, key=cmp_to_key(locale.strcoll))
# sorted 返回一个新的序列
old = [5, 2, 3, 1, 4]
new = sorted(old)
"""
结论: 没有改变以前的值,返回了一个新的序列。在某些场景比较重要。
"""
"""
直接调用数组内置的方法:
"""
old.sort()
print(old)
"""
结论:数组对象的sort方法调用比较方便,但是对原数组进行了修改。
如果不需要元素组的情况下,这样使用很好。
但是需要保留原来数组的情况下,就不很好了。
"""
"""
另外数组对象sort方法的一个弊端就是,sort方法只对数组有用。
而sorted方法可以接受所有的可迭代对象。
"""
lists = sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
print(lists)

"""
不管是list.sort()方法,还是sorted()方法,都有一个关键参数,可以指定一个
方法,这个方法会在对比前被调用,来处理可迭代对象的每一个元素,指定用元素的
哪个属性进行对比。举个例子:
"""
lists = sorted("This is a test string from Andrew".split(), key=str.lower)
"""
这个key参数指定的方法,我们称为关键方法。
这个关键方法接受一个参数,返回一个数。
这样做比较快,应为这个方法针对每条记录,只被调用一次。
"""
"""
下面是一个比较复杂的例子:针对元组
"""
student_tuples = [
    ('john', 'A', 15),
    ('jane', 'B', 12),
    ('dave', 'B', 10),
]
lists = sorted(student_tuples, key=lambda student: student[2])
"""
下面这个例子,针对对象
"""
class Student:
    def __init__(self, name, grade, age):
        self.name = name
        self.grade = grade
        self.age = age
    def __repr__(self):
        return repr((self.name, self.grade, self.age))
student_objects = [
    Student('john', 'A', 15),
    Student('jane', 'B', 12),
    Student('dave', 'B', 10),
]
lists = sorted(student_objects, key=lambda student: student.age)
"""
python 中的另外一个模块 Operator(操作模块)
上面的关键函数使用非常频繁,python提供了一些内置的关键方法,
让使用更加方便。
operator模块提供了三个方法:
itemgetter(), attrgetter(),methodcaller()
"""
from operator import itemgetter, attrgetter
lists = sorted(student_tuples, key=itemgetter(2))
lists = sorted(student_objects, key=attrgetter('age'))
"""
同时按多个字段进行排序:
"""
lists = sorted(student_tuples, key=itemgetter(1,2))
lsits = sorted(student_objects, key=attrgetter('grade', 'age'))
"""
升序和降序:
"""
lists = sorted(student_tuples, key=itemgetter(2), reverse=True)
lists = sorted(student_objects, key=attrgetter('age'), reverse=True)
"""
排序稳定性:当你指定安一个学生的年龄进行排序,两个学生的年龄一样的情况下,该如何排序?
复杂排序:允许排序进行叠加。
"""
data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
lists=sorted(data, key=itemgetter(0))

data = [('red', 2), ('blue', 2),('red', 1), ('blue', 1)]
lists=sorted(data, key=itemgetter(0))
"""
结论:python的排序会继承以前的排序。
复杂排序:
"""
# sort on secondary key,根据次要的key进行排序
s = sorted(student_objects, key=attrgetter('age'))
# now sort on primary key, descending 根据主要的key进行排序,并且降序
s = sorted(s, key=attrgetter('grade'), reverse=True)
"""
这种算法叫做:timsort算法,可以继承之前的排序结果,将多次排序结果给叠加起来。
"""
"""
The Old Way Using Decorate-Sort-Undecorate?
在对对象进行排序时候,先需要将对象装修一下,装修完以后进行排序,排序完,再把装修给毁掉。
这是一种古老的技术。我们今天已经不需要了,只是祭拜一下这种技术
"""
decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
decorated.sort()
s = [student for grade, i, student in decorated]
"""
另外一种古老技术:在以前都用cmp参数,进行排序。
在python2.4以前,没有sorted()方法,而且list.sort()没有关键方法参数。
Py2.x ,要求用户指定比较器。
py3.x, 就不需要比较器了。
下面是python2.x的写法。
"""
def numeric_compare(x, y):
    return x - y
#sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
def reverse_numeric(x, y):
    return y - x
#sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)

def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K:
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K
lists= sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))


"""
结论:
1. 对字符串进行排序,关键函数是locale.strxfrm();对比函数是: locale.strcoll()
2. reverse 参数依旧可以保持排序的稳定性。所谓的稳定性,如果排序的属性相同,则保持以前的排序
"""
data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
standard_way = sorted(data, key=itemgetter(0), reverse=True)
double_reversed = list(reversed(sorted(reversed(data), key=itemgetter(0))))
assert standard_way == double_reversed

"""
3.如果两个对象进行排序,对象需要实现__lt__()方法
"""
Student.__lt__ = lambda self, other: self.age < other.age
list = sorted(student_objects)
"""
4.关键方法不必直接依赖于排序对象
"""
students = ['dave', 'john', 'jane']
newgrades = {'john': 'F', 'jane':'A', 'dave': 'C'}
lists = sorted(students, key=newgrades.__getitem__)
最近发表
标签列表