我正在开发一个项目,我有一个类,它根据初始化的条件实现一组动态绑定方法。这样做的目的是通过创建包含一系列绑定到对象的方法的新模块,使库的功能很容易扩展,同时还将库的API简化为不积极参与的库。
它不是一个完美的并行,但为了表示这一点,我将使用一个def speak(self):
print 'Woof!'
def speak_name(self):
# This is a very talented dog
print self.name
def quack(self):
print 'Quack!'
类,在初始化时,从一个技巧模块中获取一系列技巧,在这种情况下,它将作为包含模块名称。
ABCMeta
然后,由于这些将被指定为绑定方法,因此技巧模块可以包含访问类'属性如:
__subclasshook__
现在我终于到了我努力奋斗的部分。使用instance()
类DuckABC
方法可以更改is 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
方法的类,它都返回true。
Dog
然而,这是我的问题出现的地方。使用此>>> my_dog = Dog('Berkley', 'name_of_module_containing_quack')
>>> my_dog.quack()
Quack!
>>> isinstance(my_dog, DuckABC)
False
抽象基类和上面定义的动态Dog
类,将会出现以下情况:
quack
我理解它没有返回true,因为Dog
类本身没有任何名为isinstance()
的方法,尽管{{1}}类的这个特定实例学会了如何嘎嘎。
所以我的问题是:在这个框架中有没有办法使用{{1}}方法来检查我的狗类的特定实例是否知道如何嘎嘎?如果没有,我可能有什么其他选择来实现相同的功能?
答案 0 :(得分:2)
我会更简单:
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
模块将包含mixins。您可以创建一个工厂函数来生成所需类的子类/实例:
def make_special_dog_class(class_name, *classes):
return type(class_name, tuple(classes), {})
答案 1 :(得分:1)
使用hasattr
:
if hasattr(dog, "Quack"):
dog.Quack()
else:
dog.Sit()