> I've been coding Python long enough that 'asking forgiveness instead of 
> permission' is my first instinct, but the resulting code is sometimes clumsy, 
> and I wonder if someone can suggest something I'm missing, or at least 
> validate what's going on here in some way. 
> 
> What I'm trying to do is write a file to a directory. However, the directory 
> may not exist the first time I try to write a file there, so I'm going to 
> first try to write the file, and if I get an exception, create the directory 
> (er, *try* to), and *then* write the file there.

That would work.
Though I would just try to create the error directory first. If that fails, I 
check the error message/code in the except clause: if it indicates the 
directory already exists, I pass the exception, otherwise reraise it.
Then I continue with creating the file within the directory I now am certain of 
exists.
Note 1: certain is only half: some other process could remove the directory in 
the split second between my code creating it and my code creating the file. If 
you think that could happen, you'll need to look at the other ways to do this.
Note 2: the directory can exist, but not have write access to your process. So 
between the try-except for creating a directory and the try-except for creating 
a file, you may put in a try-except for chmod. Of course, if you're not the 
owner, both the chmod and file creation will fail (I'm assuming some *nix 
platform here, btw).

> Here's my first shot at the code: 
> 
>         try:  
>             self.save_file(picfile_fullpath, picdata)
>         except IOError as err:
>             # directory doesn't exist. Try to create it.

Careful: you're not checking the actually error given by the exception. There 
may be more than one reason that the file can't be created (examples: the 
permissions mentioned above, or some file creation limit in a directory).


>             try:  
>                 os.makedirs(picfile_fullpath)
>             except OSError as oserr:
>                 logging.error("Can't create file path: %s (%s)" % 
> (picfile_fullpath, oserr))
>             else: 
>                 # Created dir, now write file.
>                 try:  
>                     self.save_file(picfile_fullpath, picdata)
>                 except IOError as err:
>                     logging.error("Bailing. Couldn't save file %s (%s)" % 
> (picfile_fullpath, err)) 
>                     return False
> 
> Doesn't this seem less readable than the 'ask permission' equivalent? I think 
> it does, but in this case asking permission for every single operation when 
> the dir will only need to be created a single time (and then may be written 
> to several hundred times) is pretty wasteful.

One of the things I once read (but I forgot where) on this issue, is the usual 
"it depends". It depends whether you except that often, the directory doesn't 
exist and the file can't directly be created. In that case, if may be quicker 
to ask permission first (simple if-statement). If you expect that in general, 
you can immediately create the file within the directory (so an exception is 
unlikely to occur), then use a try-except clause.
But don't take my word for it; I'd be curious what others on this list say 
about this.


> 
> I suppose I could set some sentinel variable and check for it in a while 
> loop, but then I need some other scaffolding code to make sure I don't 
> infinitely loop trying to create the directory, and probably some other stuff 
> I'm forgetting, so it strikes me as being just as messy. 
> 
> Is there a clean sort of pattern to apply in instances like this? 

I guess not, though readability of code is an important thing to consider. In 
this case, I don't find the correctly unreadable, but at some point, these 
things do tend to get out of hand and you're better off coding it differently 
(perhaps even using functions).


  Evert

_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to