我正在编写装饰代码(出于好奇的缘故),以便在python中创建类抽象。到目前为止,它似乎可以正常工作,但是我出现了意外的行为。

装饰的主意如下所示:

from abc import ABCMeta, abstractmethod

def abstract(cls):
    cls.__metaclass__ = ABCMeta
    return cls

然后,在使用这种装饰时,只需定义一个抽象方法
@abstract
class Dog(object):
   @abstractmethod
   def bark(self):
      pass

但是当我测试时,我可以实例化Dog对象:
d = Dog()
d.bark() //no errors
Dog.__metaclass__ //returned "<class 'abc.ABCMeta'>"

当测试直接分配__metaclass__时,它的行为符合预期:
class Dog(object):
   __metaclass__ = ABCMeta
   @abstractmethod
   def bark(self):
      pass

测试:
d = Dog()

"Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    d = Dog()
TypeError: Can't instantiate abstract class Dog with abstract methods bark"

为什么会这样呢?

最佳答案

我已经能够重现您的问题。

ABCMeta .__ new__从未使用您的装饰器称为。当您将其真正定义为Dog的元类时,它就会被调用。这是因为已经定义了Dog类,因此在之后添加ABCMeta实际上没有任何区别,因为在定义时未调用其,不会将Dog类注册为抽象类,也不会发现它的抽象方法。我邀请您阅读ABCMeta。 新的代码,您将看到它的作用。

但是,我找到了这个解决方案,仍然可以使装饰器正常工作:

def abstract(cls):
    return ABCMeta(cls.__name__, cls.__bases__, dict(cls.__dict__))

现在可以正常工作了。这意味着必须子类 Dog才能调用bark

关于python - Python抽象装饰不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32640184/

10-16 22:16