【问题标题】:How can i change the __cmp__ function of an instance (not in class)?如何更改实例的 __cmp__ 函数(不在类中)?
【发布时间】:2010-08-03 14:58:07
【问题描述】:

如何更改实例的 __cmp__ 函数(不在类中)?

例如:

class foo:
    def __init__(self, num):
        self.num = num

def cmp(self, other):
    return self.num - other.num

# Change __cmp__ function in class works
foo.__cmp__ = cmp
a = foo(1)
b = foo(1)

# returns True
a == b



# Change __cmp__ function in instance that way doesnt work
def cmp2(self, other):
    return -1

a.__cmp__ = cmp2
b.__cmp__ = cmp2

# Raise error 
a == b
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#TypeError: cmp2() takes exactly 2 arguments (1 given)

【问题讨论】:

  • 你的类应该继承自object: class foo( object ):
  • 同一类事物的不同比较例程(〜类的实例)?为什么?
  • +1 只是为了引起一些非常棒的答案 =p

标签: python metaprogramming cmp


【解决方案1】:

不要这样做

这会使您的代码出现错误且难以维护。之所以难,是因为正确的方法是继承foo

class FunkyCmpFoo( foo ):
    def __cmp__( self, other ):
        return -1

&c., &c.这样,您就知道所有foos 以​​相同的方式进行比较,并且所有FunkyCmpFoos 以相同的方式进行比较。如果你不这样做,你最终会将修改后的foo 与原始的foo 进行比较,而克苏鲁本人会从深处升起来惩罚你。

我不确定我是否应该这样说,但是it is possible,通过创建自己的instance methods

funcType = type( foo.__cmp__ )
# Alternatively:
import new
cmp2 = new.instancemethod( func, a, foo )

a.__cmp__ = funcType( cmp2, a, foo )
b.__cmp__ = funcType( cmp2, b, foo )

我可以想到一个很好的理由这样做,那就是如果你的大敌必须调试代码。事实上,我可以考虑到一些非常有趣的事情(你希望sys.maxint 如何比较小于所有偶数?)。除此之外,这是一场噩梦。

【讨论】:

  • 谢谢!我不会用“真实”的代码来做这个,只是为了好玩。
【解决方案2】:

编辑:如果你在生产代码中这样做,我应该说你是个坏人。你所有的头发和牙齿都会掉光,你将被诅咒在你的来世永远走在堆栈上。

添加一些额外的间接性,这样您就不会混淆绑定/未绑定的方法:

class foo(object):
    def __init__(self, num):
        self.num = num
        self.comparer = self._cmp

    def __cmp__(self, other):
        return self.comparer(self, other)

    @staticmethod
    def _cmp(this, that):
        print 'in foo._cmp'
        return id(this) == id(that)

    def setcmp(self, f):
        self.comparer = f

def cmp2(self, other):
    print 'in cmp2'
    return -1

a = foo(1)
b = foo(1)

print a == b

a.setcmp(cmp2)
b.setcmp(cmp2)

print a == b

【讨论】:

  • 你至少应该说不要那样做,或者实际上有人可能 =p
【解决方案3】:

* 可以使用反多态模式:

class foo(object):
    def __init__(self, num, i_am_special=None):
        self.num = num
        self.special = i_am_special

    def __cmp__(self, other):
        if self.special is not None:
            return -1
        else:
            return cmp(self.num, other.num)

    def __hash__(self):
        if self.special is not None:
            # TODO: figure out a non-insane value
            return 0

这会给出合理的结果,例如:

>>> a = foo(1)
>>> b = foo(2, 'hi mom')
>>> a > b
False
>>> b > a
False
>>> a == b
False
>>> b == b
False

我发布这个答案主要是因为我喜欢“anti-polymorphon”的声音。不要在家里这样做,没有成人监督的孩子。

[* 未经Jeff Atwood 或权利持有人Steven C. McConnell 许可使用的编码恐怖标志,我敢肯定他们是帅哥,不需要他们的标记被这样玷污。]

【讨论】:

    【解决方案4】:

    虽然为一个类的不同实例更改比较函数通常是不好的做法,但有时您可能希望对一组要执行通用操作的实例使用不同的比较函数。例如,当您想根据不同的标准对它们进行排序时。

    标准示例是sorted(list_of_foos, cmp = foocmp)。尽管目前首选使用key 参数,但实际上Python 3.x 无论如何都不支持cmp 参数(您可能希望使用cmp_to_key)。

    在这种情况下,最好的方法通常是将比较函数作为对一组实例进行操作的函数的参数,就像sorted 所做的那样。

    【讨论】:

      猜你喜欢
      • 2016-03-25
      • 2017-11-15
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多