12

I am looking for a pythonic way to create and write to file if opening it was successful or else return an error if not (e.g. permission denied).

I was reading here What's the pythonic way of conditional variable initialization?. Although I'm not sure this method works as I have attempted to test it.

os.write(fd,String) if (fd = os.open(str("/var/www/file.js"),os.O_RDWR)) else return HttpResponse("error on write")

It's supposed to be a one-liner.

When I do the above I get a syntax error as such:

    os.write(fd,String) if (fd = os.open(str("/var/www/file.js"),os.O_RDWR)) else return HttpResponse("error on write")
                               ^
SyntaxError: invalid syntax `

Is there a more and correct pythonic one-line or two-liner to be able to achieve this?

mwfearnley
  • 3,303
  • 2
  • 34
  • 35
dylan7
  • 803
  • 1
  • 10
  • 22
  • 1
    The Python ternary operator is `value1 if condition else value2`. It is not `statement1 if condition else statement2`. A return statement is not a value, so it can't be used in the ternary operator. – khelwood Mar 13 '16 at 21:13
  • Use a [`with`](http://stackoverflow.com/questions/3012488/what-is-the-python-with-statement-designed-for) statement. – PM 2Ring Mar 13 '16 at 21:21
  • Maybe just `try: with open(...) except: print("Leapt and failed. No regrets!")` unless you're only looking for ternary operator solutions. – jDo Mar 13 '16 at 21:24

4 Answers4

23
try:
  with open('filename.ext', 'w+') as f:
    f.write("Hello world!")
except IOError as e:
  # print("Couldn't open or write to file (%s)." % e) # python 2
  print(f"Couldn't write to file ({e})") # py3 f-strings

edits along the comments, thank you for your input!

2022/03 - edit for f-strings

Loïc
  • 11,804
  • 1
  • 31
  • 49
  • 8
    Gaaah! No bare `except:`s! Please use `except Exception:` if you intend to do a catch-all. But otherwise, top marks for using `with` and file as a context manager. – PaulMcG Mar 13 '16 at 21:18
  • 5
    That would be `IOError`, iirc. You shouldn't just catch all Exceptions, only the one you meant. – L3viathan Mar 13 '16 at 21:20
  • 2
    You should *really* be more explicit with your exceptions. It *really* should be IOError in this case. Keeping it at the base `Exception` is not the best choice. – idjaw Mar 13 '16 at 21:21
  • 1
    So I get `with` executes the `__enter__` and `__exit__` methods of open. However, why is it better than just `try : f =open('filename.txt','w+') f.write("hello world") except IOError as e ...` since the exception is already being caught and cleaning up. Is there something important the __enter__ and __exit__ methods of open are doing? In addition, I keep seeing `context manager` what is that? Don't wanna just use something without understanding it :). – dylan7 Mar 13 '16 at 21:26
  • 3
    @dylan7 `open` acts as a context manger, which does stuff on enter and exit. The important thing for `open` is what it does on `__exit__` — closing the file. – L3viathan Mar 13 '16 at 21:40
4

Instead of nesting the try and with statements (and missing the IOError on the way if the inner code raises one), I highly suggest this syntax. It causes one less nesting and makes sure that the IOError occurred because of the open. That way, you have no chance of catching an unwanted exception, and you have much more control.

f = None
try:
    f = open('file', 'w+')
except IOError:
    print("Couldn't open the file")
else:
    f.write('You are opened')
finally:
    if f: f.close()

There is no real pythonic way for doing it as a one liner, and it's generally a good idea to avoid long one liners.

Bharel
  • 23,672
  • 5
  • 40
  • 80
  • I think that this is problematic. On a minor note, your `print` states the reason as being "open or write", but it is only open. More fundamentally, the `open` could succeed, but the `write` fail. Finally, if explicit closing is needed, `with` (inside the `try`) would be better. – Ami Tavory Mar 13 '16 at 21:40
  • @AmiTavory Thanks, fixed. Regarding the write, failing to write and failing to open are two different things. Using a with inside a try makes it a bit harder to separate the error, don't you think? – Bharel Mar 13 '16 at 21:43
  • Not crazy about it, but maybe it's a matter of taste. Am upvoting as it does raise some different considerations than the other answers. – Ami Tavory Mar 13 '16 at 21:45
3

Since you're asking about what the Pythonic was of doing something, I think that you should consider the Ask Forgiveness, Not Permission paradigm. Namely, just perform the operation, and catch the appropriate exception if it didn't work.

For example,

In [1]: open('/usr/tmp.txt', 'w').write('hello')
---------------------------------------------------------------------------
IOError                                   Traceback (most recent call last)
<ipython-input-1-cc55d7c8e6f9> in <module>()
----> 1 open('/usr/tmp.txt', 'w').write('hello')

IOError: [Errno 13] Permission denied: '/usr/tmp.txt'

If there was no permission to do the op, an IOError will be thrown. Just catch it, then.

try:
    open('/usr/tmp.txt', 'w').write('hello')
except IOError:
    ...

Alex Martelli once talked about this, and described some inherent fallacies about checking permissions. There's an inherent race in these matters. You could always have permission to write when you opened the file, but not later when you attempted to write. You'll have to deal with exceptions anyway, so you might as well just build with them.

Community
  • 1
  • 1
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
3

If you want to be Pythonic, always go for readability when designing your code. To be honest, there is absolutely nothing wrong with wrapping something in a try/except and controlling your logic accordingly.

AKA, EAFP -> Easier to Ask for Forgiveness than Permission.

Furthermore, when you are writing to a file, you are always better off using a context manager.

So, this can easily translate in to something like this:

try:
    with open('your_file', 'w') as f:
        f.write(your_data)
except (OSError, IOError) as exc:
    print("Your file could not be written to, your exception details are: {}".format(exc))
idjaw
  • 25,487
  • 7
  • 64
  • 83
  • isn't it more pythonic to put the try in the with ? – B. M. Mar 13 '16 at 21:30
  • @B.M. What will happen if that file does not exist? It will raise. The one thing that you saying this brought to my attention though is that the exception that would raise for that would be a `FileNotFoundError`. So you would want to catch that and IOError. – idjaw Mar 13 '16 at 21:33
  • thanks, understood. IMHO, for writing, FileNotFoundError is not possible because the file doesn't allready exist. Nevertheless, open(1, 'w') raise a OSerror. – B. M. Mar 13 '16 at 22:26
  • FileNotFoundError inherits from OSError: `class FileNotFoundError(OSError):`. It *might* be better to get OSError for any other type of OSError that could come up, however. – idjaw Mar 13 '16 at 22:29