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