Is there a consensus on how to check a polymorphic instance?

Dan Perl danperl at rogers.com
Tue Nov 23 11:00:04 EST 2004


I was referring to a different kind of context in my posting.  Not exactly 
the code implementation but rather how is the code being used.  Are you the 
only one using this code and can you be confident that the function toDOM 
will be called only with objects that it is designed to handle?  Or are you 
implementing this function as part of a module that will be used by 
hundreds/thousands of users over the next ten years?

In other words, how much do you trust the test that if hasattr(xml_src, 
'documentElement') is true then "it's already a DOM object"?  What if a user 
who downloads your code off the internet 2 years from now calls toDOM with 
an object that he implemented and that has an attribute 'documentElement' 
but that object behaves in a way totally different from what you expect for 
a DOM object?  Even you may make such a mistake if you use this code again 
only one year from now, after forgetting how you implemented it.

OTOH, you may not have much of a choice but use the hasattr test in this 
case if documentElement is an attribute that is commonly used by all the DOM 
parser implementations and you want to be able to switch parsers without 
changing your code.  I am using the assumption that not all the parsers 
inherit from a common base class or else you could use isinstance with that 
class.  I am not familiar enough with XML parsers so I don't know if 
documentElement is such an attribute.

The other hasattr test in the example, for a 'read' attribute, is such a 
case.  'read' is a commonly used attribute name for methods that read data. 
It doesn't matter whether it is a file, or a stream, or a queue, or 
whatever, as long as it is readable and read() returns a string.  Mind you, 
this is still an incomplete test because it does not guarantee the string to 
be XML.  But it is probably the best choice compared to testing for all the 
possible sources of XML text that you might use.

I see actually two issues here.  One is of checking inputs and that comes 
down to safety vs. flexibility.  You make a test very strict or very 
flexible depending on many criteria.  You have to consider your users, 
future changes, etc.

The other issue is one of design.  How do you design a set of classes that 
need to follow a common interface but implement that interface in different 
ways?  You can create a base class and subclass all the other classes from 
this one.  But thanks to python's dynamic typing, if the base class is 
abstract and all its attributes are overridden in the subclasses, you may as 
well just forget about inheritance and just implement all the subclasses to 
follow an interface protocol.  That's what iterators and generators are.

So, getting back to our topic, if you use inheritance to implement your 
classes or you have only one class, then use isinstance.  If you have a set 
of classes that do not have a common base class and instead just implement 
an interface protocol, then use hasattr.  Your question was about 
polymorphic instances.  That implies inheritance, but you may want to 
consider also protocol implementation and that is what other posters are 
suggesting.

I think that an interesting question here is whether inheritance or protocol 
implementation is the preferred way in python.  I'm not sure what the answer 
is to that question.  One advantage I see in inheritance is to allow 
stronger checks like isinstance vs. hasattr.  I come from a very 
conservative background in software development and strong checks are deeply 
rooted in my mind.  But it looks to me that python is not about that or else 
it wouldn't have dynamic typing.

Dan

"Mike Meng" <meng.yan at gmail.com> wrote in message 
news:1101189570.958016.283130 at f14g2000cwb.googlegroups.com...
> Thank you Dan,
> Solution #1 is concluded from 'Text Processing in Python', section
> 1.1.3, `Pythonic Polymorphisim', around there, here is an example he
> provides:
>
> def toDOM(xml_src = None):
> from xml.dom import minidom
> if hasattr(xml_src, 'documentElement'):
> return xml_src     # it's already a DOM object
> elif hasattr(xml_src, 'read'):
> # it is something that knows how to read data
> return minidom.parseString(xml_src.read())
> elif type(xml_src) in (StringType, UnicodeType):
> # it is a filename of an XML document
> xml = open(xml_src).read()
> return minidom.parseString(xml)
> else:
> raise ValueError, "Must be initialized with " + \
> "filename, file-like object, or DOM object"
> What's your opinion?
> 





More information about the Python-list mailing list