代码:
>>> class Negative:
... pass
>>> class Positive:
... @classmethod
... def __neg__(cls):
... return Negative
所以我试试
>>> -Positive is Negative
TypeError: bad operand type for unary -: 'type'
这虽然有效
>>> -Positive() is Negative
True
其他一元运算符及其相关的“神奇”方法也是如此(例如~
和__invert__
,+
和__pos__
等。
为什么它适用于实例但不适用于类?我怎样才能让它发挥作用?
编辑:我修改了建议的代码,以便在元类中移动魔术方法。
class Negative: pass
class PositiveMeta(type):
def __neg__(cls):
return Negative
class Positive(metaclass=PositiveMeta): pass
答案 0 :(得分:4)
您的代码无法像最初编写的那样工作的原因是您无法在实例中定义魔术方法。根据{{3}}:
对于自定义类,只有在对象类型上定义的特殊方法的隐式调用才能保证正常工作,而不是在对象的实例字典中。
这适用于类(它是某些元类的实例),就像它对#34;常规"一样。对象。从这个意义上说,这个问题等同于以下任何一个问题:docs,Overriding special methods on an instance,Why does Python's bool builtin only look at the class-level __bool__ method。
使用@classmethod
修饰魔术方法与将__get__
获取的绑定方法分配给实例是一样的。在这两种情况下,Python都会忽略任何未在类中定义的描述符。
这也是-Positive() is Negative
起作用的原因。当您取消Positive
的实例时,解释器会在类中查找__neg__
。使用@classmethod
进行装饰在这里完全是多余的,因为无论如何都忽略了输入参数。但是现在你有了一个返回类对象的魔术方法。
要在类对象上正确定义魔术方法,需要在元类上定义它:
class MetaPositive(type):
def __neg__(self):
return Negative
class Negative: pass
class Positive(metaclass=MetaPositive): pass
这里有趣的是,这不仅限于一元运算符。您可以在元类上定义任何 dunder方法,并让您的类支持相应的操作:
class MetaPositive(type):
def __gt__(self, other):
if other is Negative:
return True
return False
现在您可以使用>
运算符来比较您的类。我并不是说你应该做那样的事情,但肯定存在这种可能性。
问题仍然存在,就像往常一样,为什么你想要首先做这样的事情。
答案 1 :(得分:3)
这似乎有效:
class Negative: pass
class PositiveMeta(type):
def __neg__(self):
return Negative
class Positive(metaclass=PositiveMeta):
pass
print(-Positive is Negative) # prints True
答案 2 :(得分:3)
试试这个:
class Negative:
pass
class meta(type):
def __neg__(cls):
return Negative
class Positive(metaclass=meta):
pass
-Positive
#output __main__.Negative