为了简单起见,假设我在Python中有一个Person类。该类包含firstname,lastname和dob的字段。
class Person:
def __init__(self, firstname, lastname, dob):
self.firstname = firstname;
self.lastname = lastname;
self.dob = dob;
在某些情况下,我想按姓氏排序人员列表,然后是firstname,后跟dob。在其他情况下,我想先用dob排序,然后用lastname排序,最后用firstname排序。有时我只想按名字排序。
创建第一个比较函数的天真解决方案是这样的:
def comparepeople(person1, person2):
if cmp(person1.lastname, person2.lastname) == 0:
if cmp(person1.firstname, person2.firstname) == 0:
return cmp(person1.dob, person2.dob);
return cmp(person1.firstname, person2.firstname);
return cmp(person1.lastname, person2.lastname);
似乎应该有一种简单的方法来定义这样的比较函数,使用元编程方法,我需要做的就是按优先顺序提供字段名称,而不是编写这些非常详细,丑陋的比较方法。但我最近才开始玩Python,并没有找到类似于我所描述的内容。
所以问题是,为具有多个可比构成成员的类编写比较函数的最Pythonic方法是什么?
答案 0 :(得分:10)
如果您真的想要比较功能,可以使用
def comparepeople(p1, p2):
o1 = p1.lastname, p1.firstname, p1.dob
o2 = p2.lastname, p2.firstname, p2.dob
return cmp(o1,o2)
这依赖于元组比较。如果要对列表进行排序,则不应编写比较函数,而应使用关键函数:
l.sort(key=lambda p:(p.lastname, p.firstname, p.dob))
这样做的优点是a)更短,b)更快,因为每个键只计算一次(而不是在排序过程中在比较函数中创建的吨元组)。
答案 1 :(得分:4)
这是一种方式(可能不是最快):
def compare_people_flexibly(p1, p2, attrs):
"""Compare `p1` and `p2` based on the attributes in `attrs`."""
v1 = [getattr(p1, a) for a in attrs]
v2 = [getattr(p2, a) for a in attrs]
return cmp(v1, v2)
def compare_people_firstname(p1, p2):
return compare_people_flexibly(p1, p2, ['firstname', 'lastname', 'dob'])
def compare_people_lastname(p1, p2):
return compare_people_flexibly(p1, p2, ['lastname', 'firstname', 'dob'])
这是有效的,因为getattr可用于获取由字符串命名的属性,并且因为Python会根据您对第一个不相等项的比较来比较列表。
另一种方式:
def compare_people_flexibly(p1, p2, attrs):
"""Compare `p1` and `p2` based on the attributes in `attrs`."""
for a in attrs:
c = cmp(getattr(p1, a), getattr(p2, a))
if c:
return c
return 0
这样做的好处是它不会构建两个完整的属性列表,因此如果属性列表很长,或者在第一个属性上完成了许多比较,则可能会更快。
最后,正如马丁所提到的,你可能需要一个关键功能而不是比较功能:
def flexible_person_key(attrs):
def key(p):
return [getattr(p, a) for a in attrs]
return key
l.sort(key=flexible_person_key('firstname', 'lastname', 'dob'))
答案 2 :(得分:0)
你能不能在课堂上使用比较方法,参见__cmp__和其他丰富的比较方法......