How to instantiate a different class in a constructor?

GiBo gibo at gentlemail.com
Tue Jan 23 06:09:08 EST 2007


Hi all,

I have a class URI and a bunch of derived sub-classes for example
HttpURI, FtpURI, HttpsURI, etc. (this is an example, I know there is
module urllib & friends, however my actual problem however maps very
well to this example).

Now I want to pass a string to constructor of URI() and get an instance
of one of the subclasses back. For example uri=URI('http://abcd/...')
will make 'uri' an instance of HttpURI class, not instance of URI.

To achieve this I have a list of all subclasses of URI and try to
instantiate one by one in URI.__new__(). In the case I pass e.g. FTP URI
to HttpURI constructor it raises ValueError exception and I want to test
HttpsURI, FtpURI, etc.

For now I have this code:

=====
class URI(object):
        def __new__(self, arg):
                for subclass in subclasses:
                        try:
                                instance = object.__new__(subclass, arg)
                                return instance
                        except ValueError, e:
                                print "Ignoring: %s" % e
                raise ValueError("URI format not recognized" % arg)

class HttpURI(URI):
        def __init__(self, arg):
                if not arg.startswith("http://"):
                        raise ValueError("%s: not a HTTP URI" % arg)
                self._uri = arg

class FtpURI(URI):
        def __init__(self, arg):
                if not arg.startswith("ftp://"):
                        raise ValueError("%s: not a FTP URI")
                self._uri = arg

subclasses = [HttpURI, FtpURI]

if __name__ == "__main__":
        print "Testing HTTP URI"
        uri = URI("http://server/path")
        print uri

        print "Testing FTP URI"
        uri = URI("ftp://server/path")
        print uri
=====

The problem is that ValueError exception raised in HttpURI.__init__() is
not handled in URI.__new__():

-----
~$ ./tst.py
Testing HTTP URI
<__main__.HttpURI object at 0x808572c>		# this is good
Testing FTP URI
Traceback (most recent call last):
  File "./tst.py", line 35, in <module>
    uri = URI("ftp://server/path")
  File "./tst.py", line 18, in __init__
    raise ValueError("%s: not a HTTP URI" % arg)
ValueError: ftp://server/path: not a HTTP URI	# this is bad
-----

When I change the __init__ methods of subclasses to __new__ I instead get:

-----
./tst.py
Testing HTTP URI
Traceback (most recent call last):
  File "./tst.py", line 29, in <module>
    uri = URI("http://server/path")
  File "./tst.py", line 7, in __new__
    instance = object.__new__(subclass, arg)
TypeError: default __new__ takes no parameters
-----

Does anyone have any hints on how to solve this problem? (other than
using urllib or other standard modules - as I said this is just to
demonstrate the nature of my problem).

Thanks!


GiBo



More information about the Python-list mailing list