我需要在集合和字典键中的python中执行不区分大小写的字符串比较。现在,创建不区分大小写的集合和字典子类证明非常棘手(请参阅:Case insensitive dictionary表示想法,请注意它们都使用较低 - 嘿,即使是被拒绝的PEP,尽管其范围很广有点宽广)。所以我创建了一个不区分大小写的字符串类(@AlexMartelli利用这个answer):
class CIstr(unicode):
"""Case insensitive with respect to hashes and comparisons string class"""
#--Hash/Compare
def __hash__(self):
return hash(self.lower())
def __eq__(self, other):
if isinstance(other, basestring):
return self.lower() == other.lower()
return NotImplemented
def __ne__(self, other): return not (self == other)
def __lt__(self, other):
if isinstance(other, basestring):
return self.lower() < other.lower()
return NotImplemented
def __ge__(self, other): return not (self < other)
def __gt__(self, other):
if isinstance(other, basestring):
return self.lower() > other.lower()
return NotImplemented
def __le__(self, other): return not (self > other)
我完全清楚lower
是not really enough来涵盖unicode中字符串比较的所有情况,但是我正在重构现有的代码,这些代码使用了一个更加笨重的类来进行字符串比较(内存和速度)无论如何使用lower() - 所以我可以在稍后阶段修改它 - 加上我在python 2上(如unicode
所示)。我的问题是:
我的操作员是否正确?
这个类足以满足我的目的,因为我注意在dicts中构造键并将元素设置为CIstr
个实例 - 我的目的是检查相等,包含,设置差异和类似操作。不区分大小写的方式。或者我错过了什么?
是否值得缓存字符串的小写版本(例如,在这个古老的python配方中可以看到:Case Insensitive Strings)。这个comment表明不是 - 而且我希望尽可能快地构建并尽可能小,但人们似乎包含了这个。
感谢Python 3兼容性提示!
微小的演示:
d = {CIstr('A'): 1, CIstr('B'): 2}
print 'a' in d # True
s = set(d)
print {'a'} - s # set([])
答案 0 :(得分:1)
代码大多看起来很好。我会删除__ge__
,__le__
和__ne__
中的快捷方式,然后展开它们直接调用 lower()。
快捷方式看起来像在` functools.total_ordering()中所做的那样,但它只会减慢代码速度并使测试跨类型比较变得更加困难,这种比较很难在这些方法是相互依存的。
答案 1 :(得分:1)
在您的演示中,您使用'a'
查看集合中的内容。如果您尝试使用'A'
,则无效,因为'A'
具有不同的哈希值。同样'A' in d.keys()
也是如此,但'A' in d
将是错误的。你实际上创建了一个违反所有哈希的正常契约的类型,声称它等于具有不同哈希值的对象。
您可以将此答案与有关创建专门的dicts的答案结合起来,并在尝试查找之前使用dict将任何可能的键转换为CIstr
。然后,您的所有CIstr
转换都可以隐藏在字典类中。
E.g。
class CaseInsensitiveDict(dict):
def __setitem__(self, key, value):
super(CaseInsensitiveDict, self).__setitem__(convert_to_cistr(key), value)
def __getitem__(self, key):
return super(CaseInsensitiveDict, self).__getitem__(convert_to_cistr(key))
# __init__, __contains__ etc.