Reputation: 21002
I'm using an existing Django library and I'm creating a class that I'd like to be abstract.
Let's say the class in question is BaseFoo
.
Currently, the implementation has a base class BaseFoo
.
Each time a class extending BaseFoo
is created, a metaclass adds it to a list of classes. It explicitly doesn't add BaseFoo
by doing a hard-coded test for the class name:
if name not in ('BaseFoo',):
class_list.append(new_cls)
I'd like to be able to write something like:
class MyBaseFoo(BaseFoo):
class Meta:
abstract = True
And have the metaclass skip all BaseFoo
objects that are abstract. So I guess I'm wondering how Django does the same thing with models and whether there is an easy, elegant way to do this myself.
I've looked through some of the code Django uses to define models but I could use some pointers. Also if there is an even easier way of doing this without necessarily using class Meta
I'm open to that too.
Note that I am not particularly thrilled by this solution:
class MyBaseFoo(BaseFoo):
abstract = True
class ActualFoo1(MyBaseFoo):
abstract = False
class ActualFoo2(MyBaseFoo):
abstract = False
Upvotes: 2
Views: 657
Reputation: 127467
There is no need to set abstract to False in concrete classes - it's sufficient to have this setting in the abstract classes only:
class_list = []
class CollectSubclasses(type):
def __new__(cls, name, bases, attrs):
abstract = False
if attrs.get('abstract', False):
abstract = True
del attrs['abstract']
res = super(CollectSubclasses, cls).__new__(cls, name, bases, attrs)
if not abstract:
class_list.append(res)
return res
class BaseFoo(object):
__metaclass__ = CollectSubclasses
abstract = True
class Concrete1(BaseFoo):
pass
class Abstract(BaseFoo):
abstract = True
class Concrete2(Abstract):
pass
print class_list
An alternative might be class decorators in Python 2.6, however, you would need to remove the class from the class_list in the @abstract decorator, since it has already been created when the decorator is called (and hence the metaclass was already invoked).
Upvotes: 3