我有一个类,我想覆盖__eq__()运算符.似乎我应该覆盖__ne__()运算符,但是__ne__基于__eq__这样实现它是否有意义?
class A:
def __eq__(self, other):
return self.value == other.value
def __ne__(self, other):
return not self.__eq__(other)
Run Code Online (Sandbox Code Playgroud)
或者,Python使用这些运算符的方式是否缺少某些东西,这不是一个好主意?
由于Python不提供其比较运算符的左/右版本,它如何决定调用哪个函数?
class A(object):
def __eq__(self, other):
print "A __eq__ called"
return self.value == other
class B(object):
def __eq__(self, other):
print "B __eq__ called"
return self.value == other
>>> a = A()
>>> a.value = 3
>>> b = B()
>>> b.value = 4
>>> a == b
"A __eq__ called"
"B __eq__ called"
False
Run Code Online (Sandbox Code Playgroud)
这似乎称为两种__eq__功能.只是寻找官方的决策树.
将一个功能移植到我的程序的Python 3.1分支时,我遇到了一个奇怪的错误.我将其缩小到以下假设:
与Python 2.x相比,在Python 3.x中,如果一个对象有一个__eq__方法,它就会自动消失.
这是真的?
以下是Python 3.1中发生的情况:
>>> class O(object):
... def __eq__(self, other):
... return 'whatever'
...
>>> o = O()
>>> d = {o: 0}
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
d = {o: 0}
TypeError: unhashable type: 'O'
Run Code Online (Sandbox Code Playgroud)
后续问题是,我该如何解决我的个人问题?我有一个对象ChangeTracker存储一个WeakKeyDictionary指向多个对象的对象,在过去的某个时间点为每个对象提供它们的值.每当签入现有对象时,更改跟踪器会说明其新的pickle是否与旧的pickle相同,因此在此期间说明对象是否已更改.问题是,现在我甚至无法检查给定对象是否在库中,因为它使得它引发了一个关于不可对象的对象的异常.(因为它有一个__eq__方法.)我该如何解决这个问题?
我的Flask-Restful应用程序有许多"对象".在应用程序的第一个版本中,这些是没有行为的简单数据结构,实现为Dicts或Dicts列表.
这些"对象"的属性可以改变.我使用生成器函数来跟踪更改,然后通过服务器发送事件(SSE)警告Web客户端.这通过维护要跟踪的对象的"旧"副本并将其与最新状态进行比较来工作.
在应用程序的下一个版本中,我使用SQLAlchemy从SQLite数据库填充"对象".这些对象现在实现为SQLAlchemy声明性类或此类的列表.
为了比较基于属性相等的"旧"和"新"实例,我只需要__eq__为我的SQLAlchemy对象添加一个覆盖.即,当属性具有相同的值时,实例被认为是相等/不变的.(我已在此问题的底部发布了示例代码).
从技术上讲,这是有效的,但引起了一些建筑警钟:我是否朝错误的方向航行?
a)如果我添加__eq__并__ne__覆盖SQAlchemy对象,当我后来想要将对象重新保存回数据库时,这是否会导致SQLAlchemy出现问题?
b)SQLAlchemy对象应该在我的应用程序中达到多远:是否有"pythonic最佳实践"?即,使用与DB持久性无关的业务逻辑/行为(例如跟踪更改)扩展SQLAlchemy对象是否正常/正常; 或者它们应该仅用作数据库和服务器之间的简单DTO,还有其他对象中的业务逻辑?
注意:我很清楚,通过REST apis和SSE呈现给客户端的数据应该从Web服务器和数据库中的实现细节中抽象出来,因此这不是这个问题的一部分.
sqlalchemy id equal vs reference equality https://codereview.stackexchange.com/questions/93511/data-transfer-objects-vs-entities-in-java-rest-server-application http://www.mehdi-khalili.com/ORM-反模式部分-4-持久性域模型/
class EqualityMixin(object):
# extended from the concept in :
# https://stackoverflow.com/questions/390250/elegant-ways-to-support-equivalence-equality-in-python-classes
def __eq__(self, other):
classes_match = isinstance(other, self.__class__)
a, b = deepcopy(self.__dict__), deepcopy(other.__dict__)
#compare based on equality our attributes, ignoring SQLAlchemy internal stuff
a.pop('_sa_instance_state', None)
b.pop('_sa_instance_state', None)
attrs_match = (a == b)
return classes_match and attrs_match
def __ne__(self, other):
return not self.__eq__(other)
Run Code Online (Sandbox Code Playgroud) 我是Python的新手,我想确保我覆盖__eq__并且__hash__正确,以免以后引起痛苦的错误:
(我正在使用Google App Engine.)
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())
Run Code Online (Sandbox Code Playgroud)
一个稍微复杂的类型:
class DependencyArcTail(db.Model):
''' A list of courses that is a pre-req …Run Code Online (Sandbox Code Playgroud) 在Python中,前缀为一个下划线表示不应在其类之外访问成员.这似乎是基于Java和C++的每个类.
但是,pylint似乎在每个对象的基础上强制执行此约定.有没有办法允许每个类访问而不诉诸#pylint: disable=protected-access?
class A:
def __init__(self):
self._b = 5
def __eq__(self, other):
return self._b == other._b
Run Code Online (Sandbox Code Playgroud)
结果:
pylint a.py
a.py:6: W0212(protected-access) Access to a protected member _b of a client class
Run Code Online (Sandbox Code Playgroud)
Pylint在这里描述了这条消息.
不知道这里的术语,但是这将是区别eq?和equal?的差额,方案,或者== 和strncmp与C字符串; 在每种情况下,第一个将返回false为两个不同的字符串,实际上具有相同的内容,第二个将返回true.
对于Python的AST,我正在寻找后一种操作.
现在,我这样做:
import ast
def AST_eq(a, b):
return ast.dump(a) == ast.dump(b)
Run Code Online (Sandbox Code Playgroud)
这看起来很有效,但感觉就像是等待发生的灾难.谁知道更好的方法?
编辑:不幸的是,当我去比较两个AST时__dict__,这个比较默认使用单个元素的__eq__方法.AST被实现为其他AST的树,并且它们__eq__显然检查参考标识.因此,无论是直接==还是托马斯链接的解决方案.(除此之外,我也不想将每个AST节点类型子类化以插入此自定义__eq__.)
如果我有对象列表:
l = [a, b, c]
Run Code Online (Sandbox Code Playgroud)
然后我删除其中一个对象:
l.remove(a)
Run Code Online (Sandbox Code Playgroud)
python如何确定要删除的列表中的哪个项目(引擎盖下)?
它是否使用内存位置a?(你可以查看hex(id(a)))
在Python文档中提到,如果重写__eq__和对象是不可变的,你也应该重写__hash__为了类是正确哈希的。
在实践中,当我这样做时,我通常会得到如下代码
class MyClass(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __eq__(self, other):
if type(other) is type(self):
return (self.a == other.a) and (self.b == other.b)
else:
return False
def __hash__(self):
return hash((self.a, self.b))
Run Code Online (Sandbox Code Playgroud)
这在某种程度上是重复的,并且很明显有在更新另一个更新时忘记更新一个的风险。
是否有建议的方法一起实现这些方法?
python ×10
comparison ×2
equality ×2
hash ×2
hashable ×1
list ×1
memory ×1
operators ×1
pylint ×1
python-3.x ×1
sqlalchemy ×1
user-defined ×1