没有抽象方法的抽象类在python中创建对象

时间:2018-04-30 11:28:42

标签: python abstract-class

基本上,我知道抽象基类与常规类一样被用作框架类,但强制要求抽象方法应该被子/继承类重写,如果它有下面的那样

Class AbstractClass(object):
    __metaclass__ = abc.ABCMeta

    @abstractmethod
    def absmethod(self):
        pass

class ChildClass(AbstractClass):
    def absmethod(self):
        print "Yeah!"

obj = ChildClass()

因此我们可以创建一个ChildClass对象

我们知道我们无法实例化一个抽象类,因为它只是骨架,如果我们尝试将其实例化,我们将会收到错误

obj = AbstractClass()

*** TypeError: Can't instantiate abstract class AbstractClass with abstract methods absmethod

但是我发布这个StackOverflow的实际问​​题是,如果我们使用abc.ABCMeta创建一个抽象类,而没有抽象方法,我可以创建一个抽象类的实例,它不应该是案件(如果我错了,请纠正我)

Class AbstractClass(object):
    __metaclass__ = abc.ABCMeta

obj = AbstractClass()

OOOPPPSS 它有效,我们实际上可以在没有抽象方法的情况下创建抽象类的对象吗?所以请让我知道这个

背后的关键点

4 个答案:

答案 0 :(得分:3)

来自the docs

  

具有从ABCMeta派生的元类的类不可能   实例化,除非它的所有抽象方法和属性都是   重写的。

相反,这意味着任何没有抽象方法或属性的类都可以<{1}} 实例化。

如果要禁止实例化最顶层的父类,可以编写一个自定义类,在其__new__方法中执行类型检查:

AbstractClass
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__
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)

答案 1 :(得分:1)

由于Python是一种动态语言,强制类继承特定类的想法违背了duck typing。因此,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)

答案 2 :(得分:0)

这是不使用ABC的解决方案。有关here

所需的特定情况的更多信息
DB_CONNECTION

答案 3 :(得分:0)

我通常只用 __init__ 声明基类的 @abc.abstractmethod。 如果我的基类没有 __init__,我会添加一个微不足道的。

像这样:

class AbstractClass(abc.ABC):
    @abc.abstractmethod
    def __init__(self):
        pass

    # other useful non-abstract methods...


class ChildClass(AbstractClass):
    def __init__(self):
        pass


if __name__ == '__main__':
    child = ChildClass()  # allowed
    abstract = AbstractClass()  # TypeError