Reputation: 24788
I've written the following code to help enforce the definition of certain methods for a class:
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
Which is implemented like this:
Model = createClassTemplate("Model", ["foo", "bar", "baz"])
class MyClass(Model):
pass
This way, when I'm missing a method, the calling class will generate a meaningful error indicating that I've failed to define a required method.
The problem is, the above code seems uncomfortably hacky and unpythonic. Am I going about this right way? Should I even be forcing class templates like this? And is there a better way to accomplish the same thing?
Upvotes: 1
Views: 88
Reputation: 1125248
You should use a metaclass instead.
The standard library comes with a ready-made metaclass for just this task, the ABCMeta
metaclass:
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
Demonstration:
>>> 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
Once MyClass
does provide implementations of the abstract methods, instantiation succeeds:
>>> class MyClass(Model):
... def foo(self): pass
... def bar(self): pass
... def baz(self): pass
...
>>> myclass = MyClass()
Upvotes: 2
Reputation: 80111
It seems to me that you are trying to reinvent the Abstract Base Classes
I think you want something like this:
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
Upvotes: 0
Reputation: 142256
If you're using Python 2.6+, there's the concept of an ABC - http://docs.python.org/2/library/abc.html
Upvotes: 0