Frage

In Python, I currently have instances of a class like MyClass('name1'), MyClass('name2') and so on.

I want to make it so that each instance has its own superclass, i.e., I want MyClass('name1') to be an instance of Name1MyClass and MyClass('name2') to be an instance of Name2MyClass. Name1MyClass and Name2MyClass would be dynamically generated subclasses of MyClass. I can't figure out how to do this, because it seems that Python always makes whatever is returned from __new__ an instance of that class. It isn't clear to me how to do it in a metaclass either.

The reason I want to do this is that I want to define __doc__ docstrings on the instances. But it seems that help completely ignores __doc__ on instances; it only looks on classes. So to put a different docstring on each instance, I need to make each instance have its own custom class.

War es hilfreich?

Lösung

I could be wrong, but I don't think you want a metaclass here. __metaclass__es are used when the class is created, not when you call the class to construct a new instance of the class (or something else).

Here's an answer using __new__ without a metaclass. It feels a bit hacky, but it seems to work:

_sentinel = Ellipsis
class MyClass(object):
    def __new__(cls, name):
        if name is _sentinel:
            return object.__new__(cls)
        else:
            instance = type(name + cls.__name__, (MyClass,), {})(_sentinel)
            # Initialization goes here.
            return instance

print type(MyClass('name1'))
print type(MyClass('name2'))

There's a catch here -- All the business logic of initializing then new instance must be done in __new__. Since __new__ is returning a different type than the class it is bound to, __init__ won't get called.


Another option is to create a class factory:

class MyClass(object):
    pass

def class_factory(name):
    new_cls = type(name + MyClass.__name__, (MyClass,), {})
    return new_cls() # Or pass whatever you want in here...

print type(class_factory('name1'))
print type(class_factory('name2'))

Finally, you could even create a non-__new__ class method:

class MyClass(object):
    @classmethod
    def class_factory(cls, name):
        new_cls = type(name + cls.__name__, (cls,), {})
        return new_cls() # Or pass whatever you want in here...

print type(MyClass.class_factory('name1'))
print type(MyClass.class_factory('name2'))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top