Duck类型,isinstance(),\uU子类钩子函数重写,以及types.MethodType()一起工作?

2024-09-28 01:29:53 发布

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

我在一个项目中有一个类,它根据初始化时的条件实现一组动态绑定方法。这样做的目的是通过创建一个包含一系列绑定到对象的方法的新模块,使库的功能易于扩展,同时也简化了库的API,使之不积极参与其中。在

这不是一个完美的并行,但是为了表示这一点,我将使用一个Dog类,该类在初始化时从tricks模块获取一系列技巧,在本例中,它将作为包含模块名称的字符串传递。在

class Dog(object):
    def __init__(self, name, module_name):
        self.name = name
        # imports module
        module = __import__("mylib.tricks.{mod}".format(mod=module_name),
                            from_list=['arbitrary argument'])
        # Dog object gets all tricks from module as bound methods
        tricks = module.__all__
        for trick in tricks:
             exec("self." + trick + "=types.MethodType(" + trick + ", self)")

然后,由于这些方法将被指定为绑定方法,因此tricks模块可以包含访问类属性的方法,例如:

^{pr2}$

现在我终于到了我挣扎的那部分了。使用ABCMeta__subclasshook__方法可以更改is instance()方法的行为,以便它为实现特定方法的任何类返回true。例如,我们可以有一个DuckABC抽象基类,它本质上是一个接口,对于实现quack()方法的任何类也返回true。在

class DuckABC:
    __metaclass__=ABCMeta

    @abstractmethod
    def quack(self):
        pass

    @classmethod
    def __subclasshook__(cls, instance):
        if cls is DuckABC:
            if any("quack" in class_.__dict__ for class_ in instance.__mro__):
                return True
        return NotImplemented

class Cat(object):
    def __init__(self, name):
        self.name=name
    def quack(self):
        # Not a very talented cat
        print 'meow'

>>> my_cat = Cat('Tom')
>>> isinstance(my_cat, DuckABC)
True

然而,这就是我的问题所在。使用这个DuckABC抽象基类和上面定义的动态Dog类,以下情况是正确的:

>>> my_dog = Dog('Berkley', 'name_of_module_containing_quack')
>>> my_dog.quack()
Quack!
>>> isinstance(my_dog, DuckABC)
False

我理解它没有返回true,因为Dog类本身没有任何称为quack的方法,尽管{}类的这个特定实例学会了如何嘎嘎叫。在

所以我的问题是:在这个框架中有没有任何方法可以使用isinstance()方法来检查我的dog类的特定实例是否知道如何嘎嘎作响?如果没有,我还有什么选择可以实现相同的功能?在


Tags: 模块方法nameselfobjectmydefclass
2条回答

使用hasattr

if hasattr(dog, "Quack"): 
    dog.Quack()
else: 
    dog.Sit()

我想说得简单得多:

class QuackMixin(object):
    def quack(self):
        ...

class Dog(object):
    ...

class QuackingDog(Dog, QuackMixin):
    pass

quacking_dog = QuackingDog(...)

isinstance(quacking_dog, Dog) -> True
isinstance(quacking_dog, QuackMixin) -> True
isinstance(quacking_dog, QuackingDog) -> True

所以您的tricks模块将包含mixin。您可以创建一个工厂函数来生成所需类的子类/实例:

^{pr2}$

相关问题 更多 >

    热门问题