是否可以将用户定义的类作为另一个类的实例进行有条件测试?

时间:2013-08-18 20:55:25

标签: python class instance python-3.3

通过定义类的元类的__instancecheck__()特殊方法,可以控制对象何时作为该类的成员进行测试。如果你有一个预定义的类P(比如一个内置类)并且你想有条件地控制你的类C的给定实例是否作为P类型的对象测试怎么办?可以这样做吗?

这是一个愚蠢的例子:

class C:
    def __init__ (self, x, y):
        self.x = x
        self.y = y

假设我希望C作为类numbers.Number的对象进行测试,但仅限于x > yy % 3 == 0。 (我说这将是一个愚蠢的例子。)

from numbers import Number
assert isinstance(C(4, 3), Number)
assert not isinstance(C(1, 3), Number)
assert not isinstance(C(4, 2), Number)

可以这样做吗?怎么样?

1 个答案:

答案 0 :(得分:1)

方法__instancecheck__()是在要测试的类上定义的 - 在本例中是类numbers.Number。该类使用abc.ABCMeta作为其元类(请参阅source code)。机制ABCMeta提供了更多应该被视为类实例的类register() method。为了完全满足您的要求,您必须使用numbers.Number的某个自定义子类替换ABCMeta的元类,该子类将覆盖__instancecheck__()以提供所需的功能。通过为numbers.Number.__class__分配一个新类,可以在CPython中实现这一点,但这并不能保证在其他python实现中有效。

import abc
import numbers

class C(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def is_number(self):
        return self.x > self.y and not self.y % 3

class NumberMeta(abc.ABCMeta):
    def __instancecheck__(self, obj):
        if type(obj) is C:
            return obj.is_number()
        return abc.ABCMeta.__instancecheck__(obj)

numbers.Number.__class__ = NumberMeta

assert isinstance(C(4, 3), Number)
assert not isinstance(C(1, 3), Number)
assert not isinstance(C(4, 2), Number)

那就是说,实际做这样的事情似乎是一个糟糕的主意。为什么你认为你需要这个?