1

我编写了以下代码来帮助强制定义类的某些方法:

def createClassTemplate(name, requiredMethods=[], inherits=object):
    def require(name):
        def errorRaiser(self, *args, **kwargs):
            raise RequireException("method '{}' must be defined.".format(name))
        setattr(wrapper, "__name__", name)
        return errorRaiser

    class Custom(inherits): pass

    setattr(Custom, "__name__", name)
    for methodName in requiredMethods:
        setattr(Custom, methodName, require(methodName))

    return Custom

这是这样实现的:

Model = createClassTemplate("Model", ["foo", "bar", "baz"])

class MyClass(Model):
    pass

这样,当我缺少一个方法时,调用类将生成一个有意义的错误,表明我未能定义所需的方法。

问题是,上面的代码看起来很笨拙和不符合 Python 标准。我这样做对吗?我什至应该强制使用这样的类模板吗?有没有更好的方法来完成同样的事情?

4

4 回答 4

4

您可以使用ABCMeta元类:

from abc import ABCMeta, abstractmethod

class MyClass:
    __metaclass__ = ABCMeta

    @abstractmethod
    def foo(self):
        pass

的子类MyClass必须重写foo才能被实例化。

于 2012-11-19T13:43:16.640 回答
2

您应该改用元类

标准库为这个任务提供了一个现成的元类,ABCMeta元类

import abc

class Model(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def foo(self):
        pass

    @abc.abstractmethod
    def bar(self):
        pass

    @abc.abstractmethod
    def baz(self):
        pass

class MyClass(Model):
    pass

示范:

>>> import abc
>>> class Model(object):
...     __metaclass__ = abc.ABCMeta
...     @abc.abstractmethod
...     def foo(self):
...         pass
...     @abc.abstractmethod
...     def bar(self):
...         pass
...     @abc.abstractmethod
...     def baz(self):
...         pass
... 
>>> class MyClass(Model):
...     pass
... 
>>> myclass = MyClass()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyClass with abstract methods bar, baz, foo

一旦MyClass确实提供了抽象方法的实现,实例化就会成功:

>>> class MyClass(Model):
...     def foo(self): pass
...     def bar(self): pass
...     def baz(self): pass
... 
>>> myclass = MyClass()
于 2012-11-19T13:43:30.750 回答
0

如果您使用的是 Python 2.6+,则有 ABC 的概念 - http://docs.python.org/2/library/abc.html

于 2012-11-19T13:43:50.417 回答
0

在我看来,您正在尝试重新发明抽象基类

我想你想要这样的东西:

import abc

class MyBaseClass:
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def foo(self):
        pass

    @abc.abstractmethod
    def bar(self):
        pass

    @abc.abstractmethod
    def baz(self):
        pas
于 2012-11-19T13:46:55.053 回答