2

I have some Python3 code that opens a file in write mode, writes something to it, and then closes the file. The filename is an int. For some reason, the code doesn't work as expected. When I run the f.write() statement, a 6 is printed to the screen. And when I run the f.close() statement, the string that was supposed to be written is printed to the screen.

>>> f = open(2, 'w')
>>> f.write('FooBar')
6
>>> f.close()
FooBar>>>
>>>

I checked the directory that I ran this in and the file (named 2) was not created. Can anyone explain what is going on? I suspect it has to do with the filename being an int, but I'm not sure.

martineau
  • 119,623
  • 25
  • 170
  • 301
M. Iyer
  • 115
  • 5
  • 2
    It's probably treating the int as a reference to a stream like stdout. Dare I ask why you tried to open a file whose name is an int? – BrenBarn Feb 13 '22 at 18:35
  • 2
    Assuming you're on Linux, 2 is the [file descriptor for stderr](https://stackoverflow.com/questions/5256599/what-are-file-descriptors-explained-in-simple-terms). – Silvio Mayolo Feb 13 '22 at 18:37
  • @BrenBarn `open(2)` wraps file descriptor 2 as a file object. – AKX Feb 13 '22 at 18:37
  • 1
    @AKX: Yes, but the remark at the end of the question ("the file (named 2) was not created") indicates the questioner somehow expects the integer to be used as a filename, not a descriptor. – BrenBarn Feb 13 '22 at 18:41
  • @BrenBarn Sorry, I misread... everything in a hurry. :) – AKX Feb 13 '22 at 18:41
  • 1
    Please read the fine [documentation](https://docs.python.org/3/library/functions.html#open) for the function you are calling **before** asking questions here. Stack Overflow is not intended to replace existing tutorials or documentation. – martineau Feb 13 '22 at 18:54
  • I’m voting to close this question because the OP has not done an adequate amount of research before asking the question. – martineau Feb 13 '22 at 18:56

2 Answers2

5

You're passing in a file descriptor number (2 for stderr).

  1. See the documentation for open(), emphasis mine:

    file is a path-like object giving the pathname (absolute or relative to the current working directory) of the file to be opened or an integer file descriptor of the file to be wrapped.

  2. As to why nothing happens before .close() (or .flush(): Your stream is line buffered, and you're not writing a newline.

    f = open(2, 'wb', buffering=0)
    

    to disable buffering.

If you wish to write to a file called '2', you must pass a string.

f = open('2', 'w')
AKX
  • 152,115
  • 15
  • 115
  • 172
  • 2
    You might want to also address why `6` is displayed in response to the `f.write()` call. That is, of course, the number of characters written by the call, which is what `f.write()` returns. in this case, its the length of the string `FooBar`. – CryptoFool Feb 13 '22 at 18:44
  • 1
    @CryptoFool: The reason for that is also explained in the [documentation](https://docs.python.org/3/library/io.html?highlight=write#io.TextIOBase.write) although admittedly it's *much* harder to find if you do a [simple documentation search](https://docs.python.org/3/search.html?q=write&check_keywords=yes&area=default). – martineau Feb 13 '22 at 19:05
2

Alternatively to a file name (type str) open also accepts a file descriptor (type int). 2 is the file descriptor of stderr on Linux, so you are opening the standard error stream for writing, so everything you write to that file object will appear in your terminal/console! The reason it appears only after you do file.close() is that by default the write content isn't immediately written to the file but rather kept in a buffer which gets written only when a newline \n is encountered in the write content, and of course when the file is closed. You can force a writeout to file by calling file.flush().

The reason for the 6 you get on screen is that the return value of file.write is always the number of characters that has been written.

In case you wanted to create a file with the name 2 in the current working directory, you need to wrap the 2 in quotes:

>>> f = open("2", 'w')
>>> f.write('FooBar')
6
>>> f.close()
>>> 
wjandrea
  • 28,235
  • 9
  • 60
  • 81
TheEagle
  • 5,808
  • 3
  • 11
  • 39