没有抽象方法的抽象类在python中创建对象
基本上,我知道抽象基类就像常规类一样用作骨架类,但是强制抽象方法应该被子类/继承类覆盖,如果它有像下面这样的类
Basically, I knew that abstract base classes are used as skeleton classes just like regular classes, but enforces that abstract methods should be overridden by the child/inherited classes if it has one like below
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
@abstractmethod
def absmethod(self):
pass
class ChildClass(AbstractClass):
def absmethod(self):
print "Yeah!"
obj = ChildClass()
这样我们就可以像上面一样创建一个ChildClass
的对象
So we can create an object of ChildClass
as above
我们知道我们不能实例化一个抽象类,因为它只是一个骨架,如果我们尝试如下实例化它,我们会得到一个错误
We know we can't instantiate an abstract class as it meant to be just skeleton and we will get an error if we try to instantiate it as below
obj = AbstractClass()
*** TypeError: Can't instantiate abstract class AbstractClass with abstract methods absmethod
但是我关于发布这个 StackOverflow
的实际查询是,如果我们使用 abc.ABCMeta
创建一个抽象类,没有抽象方法,我可以创建一个实例不应该是这种情况的抽象类(如果我错了,请纠正我)
But what my actual query about posting this StackOverflow
is if we create an abstract class by using abc.ABCMeta
, without abstract methods, I can able to create an instance of the abstract class which should not be the case(correct me if I am wrong)
Class AbstractClass(object):
__metaclass__ = abc.ABCMeta
obj = AbstractClass()
OOOPPPSS 成功了,我们真的可以创建一个没有抽象方法的抽象类的对象吗?所以请让我知道这背后的关键点
OOOPPPSS it worked, we can actually create an object of abstract classes without abstract methods? So please let me know the key points behind this
来自 文档:
具有从 ABCMeta
派生的元类的类不能除非它的所有抽象方法和属性都被实例化被覆盖.
A class that has a metaclass derived from
ABCMeta
cannot be instantiated unless all of its abstract methods and properties are overridden.
相反,这意味着任何没有抽象方法或属性的类,例如您的 AbstractClass
都可以被实例化.
Conversely, this means that any class with no abstract methods or properties like your AbstractClass
can be instantiated.
如果您想禁止最顶层父类的实例化,您可以编写一个自定义类,在其 __new__
方法:
If you want to disallow instantiation of the topmost parent class, you can write a custom class that performs a type check in its __new__
method:
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)
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"
您还可以编写一个 __new__
方法来防止实例化没有抽象方法的类:
You can also write a __new__
method that prevents instantiation of classes with no abstract methods:
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)
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