26

I'm sure it's intentional, so can someone explain the rationale for this behavior:

Python 2.7.2 (default, Oct 13 2011, 15:27:47) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from os.path import isdir,expanduser
>>> isdir("~amosa/pdb")
False
>>> isdir(expanduser("~amosa/pdb"))
True
>>>
>>> from os import chdir
>>> chdir("~amosa/pdb")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory: '~amosa/pdb'
>>> chdir(expanduser("~amosa/pdb"))
>>>

It's really annoying since, after all, the path with a username in it can be resolved unambiguously... I want to write code that can handle any sort of input that a user might give me, but this behavior requires me to call expanduser on every path my code has to deal with. It also means that anywhere I print that path out for the user to see, it will be slightly less legible than what they gave me.

This seems inconsistent with the concept of "duck typing" in which I generalize to mean that I expect python not to whine to me unless there's actually a problem...

amos
  • 5,092
  • 4
  • 34
  • 43
  • 8
    I don't know. As a Python developer, I appreciate the fact that Python doesn't go around magically expanding strings on me unless I explicitly request that behavior. If you implement your code properly you can probably centralize your calls to `expanduser` to make it less of an annoyance. – larsks May 07 '12 at 19:25
  • 4
    `chdir` assumes it's a literal name. And that is most definitely not what duck typing means. – Chris Eberle May 07 '12 at 19:25
  • Make a function that handles all of the behavior. Python gives you the core functionality. – Blender May 07 '12 at 19:26

2 Answers2

27

Because the underlying system calls don't recognize user paths, and the file access APIs are a fairly thin wrapper over them.

Additionally, it would be fairly surprising for non-Unix users,
if (for example) fopen("~foo") returns a "foo: no such user" error (as "~foo" is a valid file name on, for example, Windows)…
Or, similarly, if fopen("~administrator") returns an error like "Is a directory: C:\Documents and Settings\Administrator\".

Finally, as commenters have noted: you're confusing "duck typing" with "helpful shortcuts", which are two entirely different things:
- Duck typing allows me to substitute for a duck anything which quacks like a duck.
- Helpful shortcuts allow me to substitute for a duck anything which could be made to quack like a duck.(Python does not "try to make it quack" like some other languages do).

AbstProcDo
  • 19,953
  • 19
  • 81
  • 138
David Wolever
  • 148,955
  • 89
  • 346
  • 502
  • 2
    `~foo` is also a valid name on linux, and most other posixy settings. – SingleNegationElimination May 07 '12 at 19:42
  • I guess duck typing in my mind is "try to make it quack" before complaining. In this case, Python isn't trying very hard. I really like python because it's easy to write code that Just Works. But when it comes to getting python to do shell scripting, I find I'm writing a lot of my own utility code. – amos May 07 '12 at 23:59
  • 2
    Ah, yes - so that's the difference. Python does not "try to make it quack" like some other languages do (for example, Python throws errors for: `1 + "2"`, `object().foo`, and referencing an undefined variable). – David Wolever May 08 '12 at 00:56
11

In normal Unix utilities, the ~amosa syntax is handled by the shell, which is the program that invokes utilities. The utilities themselves do not know about the special ~ syntax (generally).

So if your python program is invoked by a shell on Unix, it will Just Work:

$ python -c 'import sys; print sys.argv[1]' ~drj
/home/drj

Notice how the python program above prints the expanded path, even though it clearly has no code to do the expansion itself. The shell expanded it.

David Jones
  • 4,766
  • 3
  • 32
  • 45
  • 2
    This is a useful point, since in programs accepting input from the command line, it may appear to beginners that python does do expansion, even though this is actually being done by the shell. This can lead to confusion when adding a filename programatically or from user input, where this expansion does not happen. – zstewart Jun 30 '15 at 19:15