Python 想要一个行为类似于ABC但又是元类的类吗
其中一个答案建议使用元类Python 想要一个行为类似于ABC但又是元类的类吗,python,oop,Python,Oop,其中一个答案建议使用元类 class DogType(type): def __init__(cls, name, bases, attrs): """ this is called at the Dog-class creation time. """ if not bases: return #pick the habits of direct ancestor and extend it with
class DogType(type):
def __init__(cls, name, bases, attrs):
""" this is called at the Dog-class creation time. """
if not bases:
return
#pick the habits of direct ancestor and extend it with
#this class then assign to cls.
if "habits" in attrs:
base_habits = getattr(bases[0], "habits", [])
cls.habits = base_habits + cls.habits
class Dog(metaclass=DogType):
habits = ["licks butt"]
def __repr__(self):
return f"My name is {self.name}. I am a {self.__class__.__name__} %s and I like to {self.habits}"
def __init__(self, name):
""" dog instance can have all sorts of instance variables"""
self.name = name
class Sheperd(Dog):
habits = ["herds sheep"]
class GermanSheperd(Sheperd):
habits = ["bites people"]
class Poodle(Dog):
habits = ["barks stupidly"]
class StBernard(Dog):
pass
for ix, cls in enumerate([GermanSheperd, Poodle, StBernard]):
name = f"dog{ix}"
dog = cls(name)
print(dog)
但是,这会引发一个错误:
TypeError:元类冲突:派生类的元类必须
是其所有基元类的(非严格)子类
我喜欢这个解决方案,但是我还需要classDog
像元类一样工作,这样我就可以在Dog
中定义抽象方法,这些方法需要在所有子类中传播。这可能是一种类似于def bark()
的方法,所有子狗都需要实现它
如何使Dog
既成为实现DogType
功能的元类,又成为限制子类实例化和运行方式的抽象类?如果查看ABC
类的,这就是为什么你的例子会产生元类冲突,因此,从你的例子中,你可以通过
从abc导入ABCMeta,abstractmethod
类元(ABCMeta):
通过
类基类(元类=元):
@抽象方法
定义某物(自我):
通过
类派生类(基类):
定义某物(自我):
返回1
尝试:
基类()
除类型错误外:
通过
其他:
引发异常('元类失败')
派生类()
你可以看到这个程序运行得很好 @Mistermiagi的评论提供了一些思考的素材,也让我更好地理解了ABC的实施方式。“抽象到具体”的顺序似乎是这样的:
type --> ABCMeta --> ABC --> regular class --> regular subclass --> object
这就是说,如果DogType
继承自ABCMeta
而不是type
,它仍然可以充当元类,同时允许其子类充当抽象基类,因为ABCMeta
是任何ABC
的元类。这使我们能够执行以下操作:
class DogType(ABCMeta):
def __init__(cls, name, bases, attrs):
""" this is called at the Dog-class creation time. """
if not bases:
return
#pick the habits of direct ancestor and extend it with
#this class then assign to cls.
if "habits" in attrs:
base_habits = getattr(bases[0], "habits", [])
cls.habits = base_habits + cls.habits
class Dog(metaclass=DogType):
habits = ["licks butt"]
def __repr__(self):
return f"My name is {self.name}. I am a {self.__class__.__name__} %s and I like to {self.habits}"
def __init__(self, name):
""" dog instance can have all sorts of instance variables"""
self.name = name
@abstractmethod
def print_habits(self):
for habit in self.habits:
print(habit)
class Sheperd(Dog):
habits = ["herds sheep"]
def print_habits(self):
for habit in self.habits:
print(habit)
class GermanSheperd(Sheperd):
habits = ["bites people"]
def print_habits(self):
for habit in self.habits:
print(habit)
class Poodle(Dog):
habits = ["barks stupidly"]
def print_habits(self):
for habit in self.habits:
print(habit)
class StBernard(Dog):
def print_habits(self):
for habit in self.habits:
print(habit)
for ix, cls in enumerate([GermanSheperd, Poodle, StBernard]):
name = f"dog{ix}"
print('\n', name)
print(cls)
dog = cls(name)
dog.print_habits()
我知道在上面的代码中不清楚为什么我将
print\u habits
定义为abstractmethod
,并在子类中重新实现它。我可以简单地在Dog
中定义它一次,这很好,但是在我的用例中,有一些方法需要在所有Dog
子类中强制执行,而有些则不需要 您只是想将元类应用于ABC类吗?也许。。。。你能详细说明一下吗?我对你想要实现什么有点困惑,因为你的示例代码没有方法或属性,但你需要的似乎是ABCMeta
。你能澄清一下你真正想要做什么吗?元类可以完全重新定义类的行为,因此了解实际需要的行为是非常重要的。你能举例说明元类或类应该提供什么吗?你能修改一下描述吗?代码中没有多重继承,元类
什么也不做。最简单的“解决方案”就是根本不使用元类
。我需要做的基本上就是前面链接的问题中的内容。无论如何,我已经重新格式化了整个问题。也许现在更清楚了?如果不是的话,请告诉我……我想我可能在最初的问题中给我的班级起了混淆的名字。我刚刚编辑了原始问题中的类名,请看一看。我需要元类来定义抽象基类实现的行为,而不是相反。我可能有其他基于此的抽象基类metaclass@user32882看来我提供的答案应该有效,因为它与标准的ABC课程几乎相同?您希望实现/修改什么特定行为?请注意,元类与子类是正交的。ABCMeta
和ABC
之间的关系与type
和ABCMeta
之间的关系或ABC
和普通班之间的关系不同。前者是一个isinstance
关系,其他的是issubclass
关系。我只是稍微了解一下这个东西的窍门。。。谢谢你的宝贵意见