Question

Lets say I have class SuperModel, Model, and SubModel.

I want to define a global attribute 'collection' that is the name of the class. For example, If I do:

Model.collection

it will return 'Model'.

If I subclass Model, say class SubModel(Model)

Submodel.collection

will return 'Submodel'

Is there a way to do so without explicitly rewriting the attribute for all the descendants of Model?

I was trying to get something out of metaclasses:

class SuperModel(type):
    def __new__(cls, name, base, attrs):
        if 'collection' not in attrs:
            attrs['collection'] = __name__.lower()

    return super().__new__(cls, name, base, attrs)

class Model(metaclass=SuperModel):
    pass

but when I try to subclass Model (for example class SubModel(Model)) I always get 'Model' when printing 'collection' when I'm expecting 'SubModel'.

Edit: I know there is a __name__ attribute but what if I wanted to assign the __name__ to a class variable each time the class is defined? So when subclassing Model there would be an attribute 'collection' in SubModel that equals __name__ ('SubModel').

Was it helpful?

Solution 2

You are using the module global __name__ in your metaclass. That's neither the name of your metatype nor your class.

Your metaclass is handed the name of the new class already, in the name attribute. Simply use that:

class SuperModel(type):
    def __new__(cls, name, base, attrs):
        if 'collection' not in attrs:
            attrs['collection'] = name.lower()

    return super().__new__(cls, name, base, attrs)

OTHER TIPS

There already is such an attribute built in, and it is called __name__.

>>> class Foo(object):
...     pass
>>> Foo.__name__
'Foo'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top