类对象和比较特定属性
类对象和比较特定属性
我有以下的代码。\n
class person(object): def __init__(self, keys): for item in keys: setattr(self, item, None) def __str__(self): return str(self.__dict__) def __eq__(self, other) : return self.__dict__ == other.__dict__
\n现在我想只对特定的属性(\"keys\")进行`__eq__`操作。所以我将它改为了以下代码:\n
class person(object): def __init__(self, keys): self.valid_keys = keys for item in keys: setattr(self, item, None) def __str__(self): return dict([(i, getattr(self, i)) for i in self.valid_keys ]) def __eq__(self, other) : assert isinstance(other, person) self_vals = [ getattr(self, i) for i in self.valid_keys ] other_vals = [ getattr(other, i) for i in self.valid_keys ] return self_vals == other_vals
\n我阅读了以下两篇很棒的帖子([这里](https://stackoverflow.com/questions/1061283/style-why-lt-instead-of-cmp)和[这里](https://stackoverflow.com/questions/1150177/comparing-object-attribute-in-one-array-to-an-object-attribute-in-another-array)),我的基本问题是:\n这种方法正确吗?还是有更好的方法在Python中实现?\n显然,方法有很多种,但我希望保持和遵循标准的Python风格。谢谢!!\n更新\n有人问我为什么不在类中固定属性。这是个很好的问题,我来解释一下。这个目的是将几个不相关的员工记录合并成一个完整的员工信息。例如,我从LDAP、Lotus Notes、Unix密码文件、Bugzilla数据等获取数据。每个数据源都有不同的属性,所以我将它们归纳为一个person类。这样可以快速一致地比较旧记录和新记录。希望对你有帮助。谢谢。\n** 更新2 **\n以下是我最终得到的代码:\n
class personObj(object): def __init__(self, keys): self.__dict__ = dict.fromkeys(keys) self.valid_keys = keys def __str__(self): return str([(i, getattr(self, i)) for i in self.valid_keys ]) def __eq__(self, other): return isinstance(other, personObj) and all(getattr(self, i) == getattr(other, i) for i in self.valid_keys)
\n感谢两位先生的审查!
问题的出现原因是代码中进行对象属性比较时,使用了较为复杂的方法,需要先将对象的属性逐个提取出来,然后再进行比较。这种方法虽然可行,但代码冗长且效率较低。
为了解决这个问题,可以使用一种更简洁和高效的方法。将原来的代码替换为return all(getattr(self, i) == getattr(other, i) for i in self.valid_keys)
。这里使用了一个内置函数all()
和一个生成器表达式来进行比较。生成器表达式getattr(self, i) == getattr(other, i) for i in self.valid_keys
会遍历所有的属性,并逐个比较它们的值。all()
函数会判断生成器表达式中的所有元素是否都为True,如果是,则返回True,否则返回False。
通过这种方法,可以避免先提取属性再进行比较的步骤,代码更加简洁,且效率更高。
问题的出现原因:
- getattr
函数在调用时如果没有找到对应的属性会抛出ArgumentError异常,当比较两个实例对象时,如果它们具有不同的属性键,则可能会遇到此异常。
解决方法:
- 在调用getattr
函数时,传递三个参数而不是两个参数(第三个参数是当属性不存在时返回的默认值);
- 在这种情况下,不要使用None
作为第三个参数,因为通常在属性不存在时,它是默认的值(使用一个标记值作为第三个参数);
- __str__
函数不允许返回一个字典,它必须返回一个字符串;
- 对于不可比较的对象之间的__eq__
函数调用,不应该抛出异常,而应该返回False;
- 可以使用self.__dict__
或vars(self)
来简洁地获取对象的状态(使用后者无法重新分配整个字典,但是可以更优雅地完成)。
更新后的类代码如下:
class person(object): def __init__(self, keys): self.__dict__ = dict.fromkeys(keys) def __str__(self): return str(vars(self)) def __eq__(self, other): return isinstance(other, person) and vars(self) == vars(other)
有一些小的增强(错误修复)是我一定会做的。特别是,如果调用getattr
函数时只传递两个参数,并且属性不存在,则会引发ArgumentError异常,因此在比较具有不同键的两个实例时可能会遇到此异常。为了解决这个问题,可以传递三个参数来调用getattr
函数(第三个参数是当属性不存在时返回的默认值)。需要注意的是,在这种情况下不要使用None
作为第三个参数,因为通常在属性不存在时,它是默认的值(可以使用一个标记值作为第三个参数)。另外,__str__
函数不允许返回一个字典,它必须返回一个字符串。对于不可比较的对象之间的__eq__
函数调用,不应该抛出异常,而应该返回False。
除了错误修复之外,你可以使用self.__dict__
或vars(self)
非常简洁地获取对象的状态。这个小技巧让你可以以更高的抽象级别重新设计你的类,更加简洁和高效。更新后的类代码如下:
class person(object): def __init__(self, keys): self.__dict__ = dict.fromkeys(keys) def __str__(self): return str(vars(self)) def __eq__(self, other): return isinstance(other, person) and vars(self) == vars(other)
Alex,我总是喜欢学习你的帖子。毫无疑问,你的知识和愿意分享是一流的。谢谢。在审查了你的代码之后——你还没有完全做到我想要的——所以我更新了我的学习成果。正如我在你编辑过的问题上评论的那样,如果self
中的一些键在other
中不存在,你仍然会在__eq__
中出现错误,就像我在上面的回答中提到的那样。此外,你的__eq__
函数不一定是对称的(也许a==b是真的[[或假的]],但b==a会出错...令人担忧!)。所以我仍然不清楚你想要做什么。也许进一步编辑答案,给出一些应该相等和不同的person实例的示例?