To achieve the first solution you should use a metaclass.
For example:
def add_default_meta(name, bases, attrs):
cls = type(name, bases, attrs)
cls.default = cls()
return cls
And use it as(assuming python3. In python2 set the __metaclass__
attribute in the class body):
class Animal(object, metaclass=add_default_meta):
# stuff
class NameClass(Animal, metaclass=add_default_meta):
# stuff
Note that you have repeat the metaclass=...
for every subclass of Animal
.
If instead of a function you use a class and its __new__
method to implement the metaclass, it can be inherited, i.e:
class AddDefaultMeta(type):
def __new__(cls, name, bases, attrs):
cls = super(AddDefaultMeta, cls).__new__(cls, name, bases, attrs)
cls.default = cls()
return cls
A different way to achieve the same effect is to use a class decorator:
def add_default(cls):
cls.default = cls()
return cls
@add_default
class Bird(Animal):
# stuff
Again, you must use the decorator for every subclass.
If you want to achieve the second solution, i.e. to check a == a.default
, then you can simply reimplement Animal.__new__
:
class Animal(object):
def __new__(cls, *args, **kwargs):
if not (args or kwargs) and not hasattr(cls, 'default'):
cls.default = object.__new__(cls)
return cls.default
else:
return object.__new__(cls)
This will create the empty instance whenever the first instance of the class is created and it is stored in the default
attribute.
This means that you can do both:
a == a.default
and
a == Bird.default
But accessing Bird.default
gives AttributeError
if you didn't create any Bird
instance.
Style note: Bird.Default
looks very bad to me. Default
is an instance of Bird
not a type, hence you should use lowercase_with_underscore
according to PEP 8.
In fact the whole thing looks fishy for me. You could simply have an is_empty()
method. It's pretty easy to implement:
class Animal(object):
def __init__(self, *args, **kwargs):
# might require more complex condition
self._is_empty = not (bool(args) or bool(kwargs))
def is_empty(self):
return self._is_empty
Then when the subclasses create an empty instance that doesn't pass any arguments to the base class the _is_empty
attribute will be True
and hence the inherited method will return True
accordingly, while in the other cases some argument would be passed to the base class which would set _is_empty
to False
.
You can play around with this in order to obtain a more robust condition that works better with your subclasses.