Shi*_*dla 7 python abstract-class
基本上,我知道抽象基类像常规类一样用作框架类,但强制要求子/继承类覆盖抽象方法,如果它有下面的类
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
@abstractmethod
def absmethod(self):
pass
class ChildClass(AbstractClass):
def absmethod(self):
print "Yeah!"
obj = ChildClass()
Run Code Online (Sandbox Code Playgroud)
所以我们可以创建一个ChildClass如上所述的对象
我们知道我们不能实例化一个抽象类,因为它只是骨架,如果我们试图将它实例化,我们将得到一个错误
obj = AbstractClass()
*** TypeError: Can't instantiate abstract class AbstractClass with abstract methods absmethod
Run Code Online (Sandbox Code Playgroud)
但是我对发布这个的实际查询StackOverflow是,如果我们通过使用abc.ABCMeta而不使用抽象方法创建一个抽象类,我可以创建抽象类的实例,但不应该是这种情况(如果我错了,请纠正我)
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
obj = AbstractClass()
Run Code Online (Sandbox Code Playgroud)
OOOPPPSS它有效,我们实际上可以创建一个抽象类的对象,而无需抽象方法?所以请让我知道这背后的关键点
从文档:
ABCMeta除非重写所有抽象方法和属性,否则无法实例化具有派生自元类的类。
相反,这意味着任何没有抽象方法或属性的类AbstractClass 都可以实例化。
如果你想禁止最顶层父类的实例化,你可以编写一个在其__new__方法中执行类型检查的自定义类:
class SubclassOnlyABC(object):
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kwargs):
if cls.__bases__ == (SubclassOnlyABC,):
msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
raise TypeError(msg)
return super(SubclassOnlyABC, cls).__new__(cls, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
class AbstractClass(SubclassOnlyABC):
pass
class ChildClass(AbstractClass):
pass
ChildClass() # works because it's a child class of an abstract class
AbstractClass() # throws TypeError because its parent class is "object"
Run Code Online (Sandbox Code Playgroud)
您还可以编写一个__new__方法来阻止没有抽象方法的类的实例化:
class NonEmptyABC(object):
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kwargs):
# check if ANY abstractmethod exists
for parentcls in cls.__mro__:
if any(getattr(attr, '__isabstractmethod__', False)
for attr in vars(parentcls).values()):
break
else:
msg = 'Abstract class {} cannot be instantiated'.format(cls.__name__)
raise TypeError(msg)
return super(NonEmptyABC, cls).__new__(cls, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
class EmptyAbstractClass(NonEmptyABC):
pass
class NonemptyAbstractClass(NonEmptyABC):
@abc.abstractmethod
def foo(self):
pass
class NonemptyChild(NonemptyAbstractClass):
def foo(self):
pass
NonemptyChild() # works because "foo" is an abstractmethod
EmptyAbstractClass() # throws TypeError because there are no abstractmethods
Run Code Online (Sandbox Code Playgroud)
由于 Python 是一种动态语言,因此强制类从特定类继承的想法本身就违背了鸭子类型。因此,Python 中抽象类的用例非常有限,并且出于传统原因提供了更多。不过,如果您想在不声明虚拟方法的情况下阻止类的实例化,您可以:
class AbstractClass(object):
__metaclass__ = abc.ABCMeta
def __new__(cls, *args, **kwargs):
if cls is AbstractClass:
raise Exception('Abstract class cannot be instantiatied')
return object.__new__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)