[Python-Dev] os.path.join failure mode

R. David Murray rdmurray at bitdance.com
Sat Feb 9 14:31:00 CET 2013


On Sat, 09 Feb 2013 09:59:13 +0000, Thomas Scrace <tom at scrace.org> wrote:
> If a function (or other non-string object) is accidentally passed as an
> argument to os.path.join() the result is an AttributeError:
> 
> 
> In [3]: os.path.join(fn, "path")
> > ---------------------------------------------------------------------------
> > AttributeError                            Traceback (most recent call last)
> > /home/tom/<ipython-input-3-44b097ceab04> in <module>()
> > ----> 1 os.path.join(fn, "path")
> > /usr/lib/python2.7/posixpath.pyc in join(a, *p)
> >      66         if b.startswith('/'):
> >      67             path = b
> > ---> 68         elif path == '' or path.endswith('/'):
> >      69             path +=  b
> >      70         else:
> > AttributeError: 'function' object has no attribute 'endswith'
> 
> 
> 
> It's relatively easy to run into this if you mean to pass the return value
> of a function (fn()) as the argument but accidentally forget to append
> parens (()) to the callable, thus passing the function itself instead.
> 
> Would it not be more helpful to raise a TypeError("Argument must be a
> string") than the slightly more mysterious AttributeError?
> 
> It's not the most difficult error in the world to figure out, I admit, but
> a TypeError just seems like the more correct thing to do here.

We don't generally do that kind of type checking in Python.  Sometimes the
error that results is obscure enough that adding an early check of some
sort is worth it, but this one is very clear, so I don't see that an
additional check would add much value here.

The reason we avoid such type checks is that we prefer to operate via
"duck typing", which means that if an object behaves like the expected
input, it is accepted.  Here, if we did an explicit type check for str,
it would prevent join from working on an "act alike" object that had
just enough str like methods to work correctly in os.join (for example,
some specialized object that was among other things a filename proxy).
Granted, this is pretty far-fetched for os.path.join, but the general
principle applies :)

--David


More information about the Python-Dev mailing list