Object interfaces and capabilities [was Re: File names and file objects [was Re: My Python annoyances]]

Paul Boddie paul at boddie.org.uk
Sat May 5 13:56:40 EDT 2007


Steven D'Aprano wrote:
>
> What do people think about functions that accept either a file name or a
> file object?
>
>
> def handle_file(obj):
>     if type(obj) == str:
>         need_to_close = True
>         obj = file(obj, 'r')
>     else:
>         need_to_close = False
>     do_something_with(obj.read())
>     if need_to_close:
>         data.close()
>
>
> Good idea? Bad idea? Just a matter of personal preference?

I sometimes write functions like this myself. However, the matter of
testing for file-like objects can obviously vary somewhat in terms of
personal preference and correctness. Some would argue that this is a
situation which would benefit from interfaces:

if isinstance(obj, FileLike): # or obj.implements(FileLike), perhaps
    do_something_with(obj.read())

In the original example, we can intuitively see that a file-like
object need only support the read and close methods, and in the case
of receiving a file-like object, only the read method need exist on
the object. Consequently, we can write the following:

if hasattr(obj, "read"):
    do_something_with(obj.read())

Some would rightly say that this is ridiculous: you're testing
something which will be discovered straight away. However, there can
be situations where you might want to know in advance whether the
object is suitable, especially if you may perform more than one kind
of operation on the object and where side-effects may occur - the "let
the code fail" attitude arguably doesn't hold up very well in such
cases.

The problem can then be framed in terms of being able to express the
set of required operations and whether something like interfaces is a
flexible enough means of doing so. We might have something like this:

if test_for_file(obj):
    do_something_with(obj) # not the string but the object itself

Now, we have the choice of explicitly phrasing the test ourselves...

def test_for_file(obj):
    return hasattr(obj, "read") and hasattr(obj, "close") # and ...

...or relying on an interface mechanism to do this for us, with the
possible additional overhead of declaring such interface usage when
defining or adopting classes.

It seems to me that there's a gulf between the use of interfaces, with
the cost of introducing declarations in the code and the benefit of
relatively easy verification of object "capabilities", and the current
situation where one might like to try and deduce the required
capabilities of an object at any given point in the code. Without
interfaces, such verification is difficult but there's less overhead
for the programmer; with interfaces, verification is easier but the
programmer has to work harder to do most of the work. I can't really
see a good compromise.

Paul




More information about the Python-list mailing list