代码之家  ›  专栏  ›  技术社区  ›  Nick Heiner

Python:这是重写eq和hash的好方法吗?

  •  19
  • Nick Heiner  · 技术社区  · 14 年前

    我是Python的新手,我想确保我的代码过了 __eq__ __hash__ 正确,以免以后造成痛苦的错误:

    class Course(db.Model):
        dept_code = db.StringProperty()
        number = db.IntegerProperty()
        title = db.StringProperty()
        raw_pre_reqs = db.StringProperty(multiline=True)
        original_description = db.StringProperty()
    
        def getPreReqs(self):
            return pickle.loads(str(self.raw_pre_reqs))
    
        def __repr__(self):
            title_msg = self.title if self.title else "Untitled"
            return "%s %s: %s" % (self.dept_code, self.number, title_msg)
    
        def __attrs(self):
            return (self.dept_code, self.number, self.title, self.raw_pre_reqs, self.original_description)
    
        def __eq__(self, other):
            return isinstance(other, Course) and self.__attrs() == other.__attrs()
    
        def __hash__(self):
            return hash(self.__attrs())
    

    稍微复杂一点的类型:

    class DependencyArcTail(db.Model):
        ''' A list of courses that is a pre-req for something else '''
        courses = db.ListProperty(db.Key)
    
        ''' a list of heads that reference this one '''
        forwardLinks = db.ListProperty(db.Key)
    
        def __repr__(self):
            return "DepArcTail %d: courses='%s' forwardLinks='%s'" % (id(self), getReprOfKeys(self.courses), getIdOfKeys(self.forwardLinks))
    
        def __eq__(self, other):
            if not isinstance(other, DependencyArcTail):
                return False
    
            for this_course in self.courses:
                if not (this_course in other.courses):
                    return False
    
            for other_course in other.courses:
                if not (other_course in self.courses):
                    return False
    
            return True
    
        def __hash__(self):
            return hash((tuple(self.courses), tuple(self.forwardLinks)))
    

    一切都好吗?

    class DependencyArcTail(db.Model):
        ''' A list of courses that is a pre-req for something else '''
        courses = db.ListProperty(db.Key)
    
        ''' a list of heads that reference this one '''
        forwardLinks = db.ListProperty(db.Key)
    
        def __repr__(self):
            return "DepArcTail %d: courses='%s' forwardLinks='%s'" % (id(self), getReprOfKeys(self.courses), getIdOfKeys(self.forwardLinks))
    
        def __eq__(self, other):
            return isinstance(other, DependencyArcTail) and set(self.courses) == set(other.courses) and set(self.forwardLinks) == set(other.forwardLinks)
    
        def __hash__(self):
            return hash((tuple(self.courses), tuple(self.forwardLinks)))
    
    1 回复  |  直到 6 年前
        1
  •  16
  •   Alex Martelli    14 年前

    1. 中可能有重复项 .courses
    2. 具有相同属性的两个实体 .课程 但不一样 .forwardLinks 会比较相等但哈希不同

    def __eq__(self, other):
        if not isinstance(other, DependencyArcTail):
            return False
    
        return (set(self.courses) == set(other.courses) and
                set(self.forwardLinks) == set(other.forwardLinks))
    
    def __hash__(self):
        return hash((frozenset(self.courses), frozenset(self.forwardLinks)))
    

    对一个对象的“真实价值”至关重要,否则两者都应该忽略 __eq__ __hash__ .

    编辑 :从中删除 __散列__ 呼叫 tuple 充其量是多余的(而且可能是有害的,正如@Mark[[tx!!!]]的评论所建议的那样);改变 set frozenset 在散列中,正如@Phillips[[tx!!!]]的评论所建议的那样。