使用try、assert、excep定义自定义的eq方法的python方法

2024-09-29 21:34:36 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的代码有效(编辑:实际上,事实证明它不起作用!),但我不喜欢出现在try: except:块之后的挂起return True语句。在

class MySlottedClass(object):
    def __new__(klass, **slots):
        klass.__slots__ = []
        for k in slots:
            klass.__slots__.append(k)
        return super(MySlottedClass,klass).__new__(klass)
    def __init__(self, **slots):
        for k,v in slots.items():
            setattr(self,k,v)
        super(MySlottedClass,self).__new__()
    def __eq__(self, other):
        for slot in self.__slots__:
            try:
                assert getattr(self, slot) == getattr(other,slot), "Not Equal"
            except (AssertionError, AttributeError):
                return False
        return True

##Testing
##Note that the above class definition is just a skeleton
##The below objects are created using 4 different but identically defined classes
##In the actual problem, I am using a metaclass to make these classes dynamically
msc1 = MySlottedClassABC(a=1,b=1,c=3)
msc2 = MySlottedClassAB(a=1,b=1)
msc3 = MySlottedClassBA(b=2,a=1)
msc4 = MySlottedClassXY(x=1,y=2)

assert msc1!=msc2
assert msc2==msc3
assert msc3==msc2
assert msc2!=msc4

为这个类编写__eq__方法有没有更为python式的方法?在


Tags: inselfnewforreturndefassertslot
3条回答

似乎您正在尝试重新创建^{}。使用namedtuple将允许在上动态创建类、测试相等性和其他有趣的事情。缺点是,由于元组是不可变的,所以to是namedtuples,因此必须创建一个新对象,而不是更新属性。{slot{or你的slots}顺序不能同时检查。在

用法示例:

from collections import namedtuple

MySlottedClassAB = namedtuple("MySlottedClassAB", ['a', 'b'])
MySlottedClassABC = namedtuple("MySlottedClassABC", ['a', 'b', 'c'])

class MySlottedClassBA(namedtuple("MySlottedClassBA", ['b', 'a'])):
    def addAB(self):
        return self.a + self.b

msc1 = MySlottedClassAB(a=1, b=2)
msc2 = MySlottedClassBA(b=2, a=1)
msc3 = MySlottedClassABC(1, 2, 3)

print(msc1)
print(msc2)
print(msc3)
print("{} == {} is {}".format(msc1, msc1, msc1==msc1))
print("{} == {} is {}".format(msc1, msc2, msc1==msc2))
print("{} == {} is {}".format(msc1, msc3, msc1==msc3))
print("msc2.addAB() is {}".format(msc2.addAB()))

如果插槽的顺序和易变性很重要,那么下面的工作就可以了(对于python2)。在

^{pr2}$

这项研究指出__slots__在几乎所有情况下都是过度杀伤。Guido Van Rossum指出,基于对新样式类中属性查找性能的无根据担忧,它们是一个过早的优化。Guido还声明,__slots__可以减少程序的内存占用,当您需要创建小对象的时候。在

I feared that all of the changes in the [new] class system were going to have a negative impact on performance. ... Thus the use of __slots__ was a way to optimize the lookup of data attributes—a fallback, if you will, in case people were disappointed with the performance impact of the new class system. This turned out unnecessary, but by that time it was of course too late to remove __slots__.

http://python-history.blogspot.co.uk/2010/06/inside-story-on-new-style-classes.html

呃,我从没想过。很明显:

    def __eq__(self, other):
        try:
            for slot in self.__slots__:
                assert getattr(self, slot) == getattr(other,slot), "Not Equal"
        except (AssertionError, AttributeError):
            return False
        else:
            return True

我可能应该结束这个问题,这样我就不会显得太傻了。


编辑:不,不好!在

多亏了大家的帮助,我现在才明白,用这种方式做事有很多问题。首先,我不应该为此使用assert,因为它主要用于测试,并且可以关闭。其次,代码没有给出MySlottedClass(a=1,b=2)==MySlottedClass(a=1,b=2,c=3)的预期结果。在

我想出了这个办法。请注意,类定义重复了4次,这样我就可以测试下面不同类的对象的比较;但是,在创建它们的实例之前,所有类都是相同的。还要注意,在实际的用例中,我使用元类自动生成这些类(并且__eq__被定义为该元类的一部分)。在

^{pr2}$

测试步骤如下:

##Testing
msc1 = MySlottedClassABC(a=1, b=2, c=3)
msc2 = MySlottedClassAB(a=1, b=2)
msc3 = MySlottedClassBA(b=2, a=1)
msc4 = MySlottedClassXY(x=1, y=2)


assert msc1 != msc2
assert msc2 != msc1
assert msc2 == msc3
assert msc3 == msc2
assert msc3 != msc4
assert msc4 != msc3

然而,在测试了Joran Beasley's answer之后,我惊讶地发现,它生成的结果与上面的结果完全相同,代码更短、更合理。因此,实现这一点的最佳方法似乎是简单地比较两个__dict__属性。在

return True很好。我认为更大的问题是使用assert进行流控制。如果用户在命令行上将-O传递给python,则断言根本不运行。你应该写更多这样的东西:

for slot in self.__slots__:
    if not hasattr(other, slot) or getattr(self, slot) != getattr(other,slot):
        return False
return True

另外,__slots__需要在类级别定义才能工作,而不是在__init__内部定义:

^{pr2}$

如果项目数可变,则可能根本不应该使用__slots__。在

相关问题 更多 >

    热门问题