如何在Python中使类或方法抽象?

我尝试像这样重新定义__new__():

class F:
    def __new__(cls):
        raise Exception("Unable to create an instance of abstract class %s" %cls)

但是现在,如果我创建一个从F继承的类G,像这样:

class G(F):
    pass

然后,我也不能实例化G,因为它调用它的超类的__new__方法。

是否有更好的方法来定义抽象类?


当前回答

老式的(pre-PEP 3119)方法是在调用抽象方法时在抽象类中引发NotImplementedError。

class Abstract(object):
    def foo(self):
        raise NotImplementedError('subclasses must override foo()!')

class Derived(Abstract):
    def foo(self):
        print 'Hooray!'

>>> d = Derived()
>>> d.foo()
Hooray!
>>> a = Abstract()
>>> a.foo()
Traceback (most recent call last): [...]

它没有像使用abc模块那样好的属性。您仍然可以实例化抽象基类本身,并且直到在运行时调用抽象方法时才会发现错误。

但是如果您处理的是一小组简单类,可能只有几个抽象方法,那么这种方法比费力地查阅abc文档要容易一些。

其他回答

老式的(pre-PEP 3119)方法是在调用抽象方法时在抽象类中引发NotImplementedError。

class Abstract(object):
    def foo(self):
        raise NotImplementedError('subclasses must override foo()!')

class Derived(Abstract):
    def foo(self):
        print 'Hooray!'

>>> d = Derived()
>>> d.foo()
Hooray!
>>> a = Abstract()
>>> a.foo()
Traceback (most recent call last): [...]

它没有像使用abc模块那样好的属性。您仍然可以实例化抽象基类本身,并且直到在运行时调用抽象方法时才会发现错误。

但是如果您处理的是一小组简单类,可能只有几个抽象方法,那么这种方法比费力地查阅abc文档要容易一些。

晚些时候回答这里,但要回答另一个问题“如何做出抽象方法”哪一点在这里,我提供如下。

# decorators.py
def abstract(f):
    def _decorator(*_):
        raise NotImplementedError(f"Method '{f.__name__}' is abstract")
    return _decorator


# yourclass.py
class Vehicle:
    def add_energy():
       print("Energy added!")

    @abstract
    def get_make(): ...

    @abstract
    def get_model(): ...

类基类Vehicle仍然可以实例化用于单元测试(与ABC不同),并且python会引发异常。哦,是的,为了方便起见,您还可以使用此方法在异常中获得抽象的方法名。

你也可以利用__new__方法。你只是忘记了一些东西。 __new__方法总是返回new对象,所以你必须返回它的超类的new方法。请按照以下步骤操作。

class F:
    def __new__(cls):
        if cls is F:
            raise TypeError("Cannot create an instance of abstract class '{}'".format(cls.__name__))
        return super().__new__(cls)

在使用新方法时,必须返回对象,而不是None关键字。这就是你错过的。

Most Previous answers were correct but here is the answer and example for Python 3.7. Yes, you can create an abstract class and method. Just as a reminder sometimes a class should define a method which logically belongs to a class, but that class cannot specify how to implement the method. For example, in the below Parents and Babies classes they both eat but the implementation will be different for each because babies and parents eat a different kind of food and the number of times they eat is different. So, eat method subclasses overrides AbstractClass.eat.

from abc import ABC, abstractmethod

class AbstractClass(ABC):

    def __init__(self, value):
        self.value = value
        super().__init__()

    @abstractmethod
    def eat(self):
        pass

class Parents(AbstractClass):
    def eat(self):
        return "eat solid food "+ str(self.value) + " times each day"

class Babies(AbstractClass):
    def eat(self):
        return "Milk only "+ str(self.value) + " times or more each day"

food = 3    
mom = Parents(food)
print("moms ----------")
print(mom.eat())

infant = Babies(food)
print("infants ----------")
print(infant.eat())

输出:

moms ----------
eat solid food 3 times each day
infants ----------
Milk only 3 times or more each day

这个方法也很简单:

class A_abstract(object):

    def __init__(self):
        # quite simple, old-school way.
        if self.__class__.__name__ == "A_abstract": 
            raise NotImplementedError("You can't instantiate this abstract class. Derive it, please.")

class B(A_abstract):

        pass

b = B()

# here an exception is raised:
a = A_abstract()