Class factory functions

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Sun Mar 25 05:51:39 EDT 2007


Here's a simple class-factory function that returns a sub-class of the
old-style class it is passed.

def verbosify_oclass(klass):
	"""Returns a verbose sub-class of old-style klass."""
	class VClass(klass):
		def __init__(self, *args, **kwargs):
			print "Calling initializer __init__ ..."
			klass.__init__(self, *args, **kwargs)
	return VClass


Here it is in action:

>>> class Parrot:
...     def __init__(self, colour): self.colour = colour
...
>>> VParrot = verbosify_oclass(Parrot)
>>> bird = VParrot('red')
Calling initializer __init__ ...
>>> bird.colour
'red'


Here's an equivalent for new-style classes. It uses super() because I
understand that super() is preferred to calling the super-class by name.


def verbosify_nclass(klass):
    """Returns a verbose sub-class of new-style klass."""
    class VClass(klass):
        def __new__(cls, *args, **kwargs):
            print "Calling constructor __new__ ..."
            return super(klass, cls).__new__(cls, *args, **kwargs)
        def __init__(self, *args, **kwargs):
            print "Calling initializer __init__ ..."
            super(klass, self).__init__(*args, **kwargs)
    return VClass



But it doesn't work:

>>> vint = verbosify_nclass(int)
>>> vint(42)
Calling constructor __new__ ...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __new__
TypeError: object.__new__(VClass) is not safe, use int.__new__()


What am I doing wrong? 


Here's one solution: dump the call to super() and call the super-class
directly. It seems to work. Are there any problems in not using super()?
What about multiple inheritance?


def verbosify_nclass2(klass):
    """Returns a verbose sub-class of new-style klass."""
    class VClass(klass):
        def __new__(cls, *args, **kwargs):
            print "Calling constructor __new__ ..."
            return klass.__new__(klass, *args, **kwargs)
        def __init__(self, *args, **kwargs):
            print "Calling initializer __init__ ..."
            super(klass, self).__init__(*args, **kwargs)
    return VClass



-- 
Steven.




More information about the Python-list mailing list