【问题标题】:Comparing string to list of objects with repr使用 repr 将字符串与对象列表进行比较
【发布时间】:2018-09-07 15:28:41
【问题描述】:

如果我有一个名为 Person 的类,并且这个类包含每个人的姓名、年龄等,如果我用 Person 类填充一个列表,我想检查一个名字是否在列表中,而不创建一个新的只是名称的列表。如果我使用 repr 并返回 repr(self.name),我可以打印列表并让它返回列表中每个人的姓名列表。如果我然后检查“史蒂夫”是否在列表中,它会返回 False。我猜这是因为它将“史蒂夫”与每个班级进行比较,而不是班级repr。有没有办法在不创建新列表的情况下做到这一点?

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __repr__(self):
        return repr(self.name)

people = [Person('steve', 25), Person('dan', 30),Person('heather', 19)]
print(people)
print('steve' in people)

【问题讨论】:

    标签: python-3.x repr


    【解决方案1】:

    使用any():

    any(p.name == 'steve' for p in people)
    #True
    

    ...和一个失败的测试:

    any(p.name == 'bob' for p in people)
    #False
    

    但是,为了能够使用in,您需要定义__eq__,而不是__repr__:

    class Person(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def __eq__(self, s):
            return s == self.name
    

    现在它按预期工作了:

    'steve' in people
    #True
    
    'bob' in people
    #False
    

    【讨论】:

    • 可能想要将 eq 修改为更像 return (s == self.name) if isinstance(s, str) else super().__eq__(s) 的东西,这样您就不会无法比较两个 Person 对象
    • 另外,这个__eq__ 解决方案虽然非常漂亮(老实说是个好主意),但会导致性能非常缓慢,尤其是当您需要在列表中查找多个名称时。如果这些in 检查是程序的重要/频繁部分,或者Persons 的数量可能会变大,则有必要使用基于散列或树的数据结构
    • 一个混合解决方案是实现一个返回hash(self.name)的__hash__,然后结合这个修改后的__eq__函数将允许您创建一组Person对象并执行'steve' in set(persons)
    • 列表不会变得很大,所以我现在不担心搜索速度,但如果需要显着扩大,我会考虑到这一点。谢谢!
    • @scnerd 你的第一点是不必要的,__eq__ 无论如何都会在两个对象中调用。
    【解决方案2】:

    最简单的方法可能是手动执行此操作:

    steve_in_people = any('steve' == repr(person) for person in people)
    

    您还可以使用布隆过滤器快速确定“steve”是否在您的列表中,但是如果不检查列表就无法确定。您还可以使用 B-Tree 之类的东西非常快速地执行此检查(最坏的情况是 O(m),其中 m 是您要查找的字符串的长度)。

    如果您不想要花哨的数据结构并且更喜欢 Python 风格...那么,请使用一个集合,这将为您提供非常高性能的 in 检查(几乎是恒定时间):

    names = {repr(person) for person in people}
    steve_in_people = 'steve' in names
    

    @JoeIddon 提出了一个很好的观点,即修改类以轻松支持这种行为。我建议进一步改进:

    class Person(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __repr__(self):
            return self.name
    
        def __eq__(self, s):
            return s == self.name
    
        # This will allow you to quickly find this object in a set using its name
        def __hash__(self):
            return hash(self.name)
    

    现在您可以创建一组Person 对象并使用名称字符串对其进行搜索:

    person_set = set(all_person_objects)
    steve_in_people = 'steve' in person_set
    

    【讨论】:

      猜你喜欢
      • 2013-02-12
      • 2023-03-23
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-06
      相关资源
      最近更新 更多