As a complete beginner to programming, I am trying to understand the basic concepts of opening and closing files. One exercise I am doing is creating a script that allows me
The default python interpeter, CPython, uses reference counting. This means that once there are no references to an object, it gets garbage collected, i.e. cleaned up.
In your case, doing
open(to_file, 'w').write(indata)
will create a file object for to_file, but not asign it to a name - this means there is no reference to it. You cannot possibly manipulate the object after this line.
CPython will detect this, and clean up the object after it has been used. In the case of a file, this means closing it automatically. In principle, this is fine, and your program won't leak memory.
The "problem" is this mechanism is an implementation detail of the CPython interpreter. The language standard explicitly gives no guarantee for it! If you are using an alternate interpreter such as pypy, automatic closing of files may be delayed indefinitely. This includes other implicit actions such as flushing writes on close.
This problem also applies to other resources, e.g. network sockets. It is good practice to always explicitly handle such external resources. Since python 2.6, the with statement makes this elegant:
with open(to_file, 'w') as out_file:
out_file.write(in_data)
TLDR: It works, but please don't do it.