Python Forum

Full Version: I need some clarity on the use of the open command
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2
I am looking at some code someone else wrote in which open is used then again on the same file that is already open. In VB, another language I use, something like this would raise an error and be denied. My main question is, what is the reason for the double opening, as you'll see in the following snippets

def CreateFile(FilePath):
    file = open(FilePath, 'w')
    header=["Court", "Location", "Citation Number", "Case Description","File Date"]
    with open(FilePath, 'a',encoding="utf-8",newline="") as f:
        writer = csv.writer(f)
        writer.writerow(header)
    return file

filepath="C:\working\access\md\maryland"
filename='Maryland Case Search.csv'
fullpath=os.path.join(filepath,filename)
if (os.path.exists(fullpath)==False):
    file=CreateFile(fullpath)
Is a new instance of the file open in the 'with open' call or does it create a pointer to the previously opened instance? I suppose If only the with call was used the file would have closed when the function ends. If that's the reason for the first call to open, why couldn't that have used all the necessary arguments, write the header, then return?
The function is only called if the file (Maryland Case Search.csv) does not exist (the if branch; line 4). In that case, it is created at line 2 of the function (which simply creates an empty file); the rest of the function then creates the csv header, opens said file then writes the header, after which the file is auto closed.

I assume that the rest of the code (not shown) goes on to use the returned file handler.
The end result is that anything written to file "f" is overwritten by writes to file "file". This can be show with a small test program.
x = open("junk.txt", "w")
with open("junk.txt", "a") as y:
    y.write("This is a test")
    print(y.tell())
print(x.tell())
x.write("Hello World!")
output
Output:
14 0
file junk.txt
Quote:Hello World!st
The reason this happens is because "x" and "y" are different file objects. Writing to file "y" does not change the file pointer in file object "x". When you write to file "x" it begins writing at position 0, not position 14.
(Nov-07-2022, 04:59 AM)deanhystad Wrote: [ -> ]The end result is that anything written to file "f" is overwritten by writes to file "file". This can be show with a small test program.
x = open("junk.txt", "w")
with open("junk.txt", "a") as y:
    y.write("This is a test")
    print(y.tell())
print(x.tell())
x.write("Hello World!")
output
Output:
14 0
file junk.txt
Quote:Hello World!st
The reason this happens is because "x" and "y" are different file objects. Writing to file "y" does not change the file pointer in file object "x". When you write to file "x" it begins writing at position 0, not position 14.

Is it then the case that the header will later be overwritten with the first record written to the file by the calling function which File was returned to?
(Nov-07-2022, 04:26 AM)rob101 Wrote: [ -> ]The function is only called if the file (Maryland Case Search.csv) does not exist (the if branch; line 4). In that case, it is created at line 2 of the function (which simply creates an empty file); the rest of the function then creates the csv header, opens said file then writes the header, after which the file is auto closed.

I assume that the rest of the code (not shown) goes on to use the returned file handler.

I understood that CreateFile is called only if the file didn't exist. The puzzling part is line 2 in CreateFile. In your reply you said it only created the file, but doesn't it also open the file it created? if so, then I take it that Python allows multiple instances of a file to be simultaneously open. With another language I use, I would have had to closed the file after creation, then open it again - so there is only 1 open instance. But since opening a file in write mode creates it if needed, why was a second instance needed to open in 'f', rather than writing the header to 'File' and returning it?
(Nov-07-2022, 08:51 AM)JonWayn Wrote: [ -> ]In your reply you said it only created the file, but doesn't it also open the file it created?

I don't think so, but I'm sure I (or you) could write a simple script to test this.

I've seen this done (that is to say, the routine that you posted) many times and I use it myself, but as it seems to be a very common way to perform such operations, I've not questioned it: it's good that you are asking such questions and I'm sure a simple test will provide the answers.

To add: have a look at the posts above, as I think the answer is there.

Another addition: Yes, the file is both created and opened. You can add a line file.close() beneath file = open(FilePath, 'w') if you so wish, but I don't think it matters so much.
Post whole code if it's more,it will not work as it is now.
If the fullpath exists code will do nothing,if fullpath dos not exists will call function CreateFile and it will give FileNotFoundError.
Have to make a directory if not exists be calling os.makedirs.
This is written by someone new to Python,shall not write it like this.
if (os.path.exists(fullpath)==False):
    file = CreateFile(fullpath)
Like this
if not os.path.exists(fullpath):
    file = CreateFile(fullpath)
To write a test that make more sense,and just open file object line 2 and return it emtpy make no sense,so just remove.
import csv
import os

def create_file(file_path):
    header = ['Court', 'Location','Citation Number', 'Case Description', 'File Date']
    with open(file_path, 'a', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(header)

filepath = r'G:\div_code\test_cs1'
filename = 'data.csv'
fullpath = os.path.join(filepath, filename)
if not os.path.exists(fullpath):
    # Folder dos not exists,make it
    os.makedirs(filepath)
    fullpath = os.path.join(filepath, filename)
    file = create_file(fullpath)
else:
    # The folder/file exists call function
    file = create_file(fullpath)
I think it is a logic error. I can think of no reason why you would open a file and write contents only to have them overwritten. Some sort of default file content? Two things make me think the code is a logic error.
1. The file open modes don't make any sense.
2. I think I know what they are trying to do and they did it wrong.

There is no reason to open the file using mode="a". You just opened the file using mode="w" and have done no writes. The file is empty. Why open with mode="a"? This code works exactly the same on my windows computer as the original code that used mode="a".
def CreateFile(FilePath):
    file = open(FilePath, 'w')
    header=["Court", "Location", "Citation Number", "Case Description","File Date"]
    with open(FilePath, 'w',encoding="utf-8",newline="") as f:
        writer = csv.writer(f)
        writer.writerow(header)
    return file
Opening the file with mode = "a" gives the impression that the file has content and the new write will appear after the existing content. There cannot be any content in the file because it was wiped out by the open two lines above with mode = "w".

One of the file opens sets the newline and the other doesn't. Setting the newline = "" is a fix for an annoying behavior csv_writer has on windows machines. From the csv documentation.
Quote:If newline='' is not specified, newlines embedded inside quoted fields will not be interpreted correctly, and on platforms that use \r\n linendings on write an extra \r will be added. It should always be safe to specify newline='', since the csv module does its own (universal) newline handling
This makes me think the purpose of the code is to open the file using newline="" so the header can be written without writing the extra \r on windows machines. Then the file is re-opened without setting newline so it can be written by other code that doesn't behave the same way as csv.writer.

If that is the case, the code should be written like this:
def CreateFile(FilePath):
    # Opening file with newline="" to avoid extra \r that csv.writer adds on windows machines
    header=["Court", "Location", "Citation Number", "Case Description","File Date"]
    with open(FilePath, 'w', encoding="utf-8", newline="") as f:
        writer = csv.writer(f)
        writer.writerow(header)
    # Reopen file for appending without newline=""
    return open(FilePath, 'a', encoding="utf-8")
Well, really it should be written like this:
import contextlib

@contextlib.contextmanager
def CreateFile(FilePath, encoding="utf-8"):
    file = open(FilePath, 'w', encoding=encoding)
    file.write("Court,Location,Citation Number,Case Description,File Date\n")
    yield file
    file.close()
Now you can do this:
with CreateFile("C:/working/access/md/maryland/Maryland Case Search.csv") as file:
    # do stuff with file

# File automatically closes when leaving context
(Nov-07-2022, 01:19 PM)snippsat Wrote: [ -> ]Post whole code if it's more,it will not work as it is now.
If the fullpath exists code will do nothing,if fullpath dos not exists will call function CreateFile and it will give FileNotFoundError.
Have to make a directory if not exists be calling os.makedirs.
This is written by someone new to Python,shall not write it like this.
if (os.path.exists(fullpath)==False):
    file = CreateFile(fullpath)
Like this
if not os.path.exists(fullpath):
    file = CreateFile(fullpath)
To write a test that make more sense,and just open file object line 2 and return it emtpy make no sense,so just remove.
import csv
import os

def create_file(file_path):
    header = ['Court', 'Location','Citation Number', 'Case Description', 'File Date']
    with open(file_path, 'a', encoding='utf-8', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(header)

filepath = r'G:\div_code\test_cs1'
filename = 'data.csv'
fullpath = os.path.join(filepath, filename)
if not os.path.exists(fullpath):
    # Folder dos not exists,make it
    os.makedirs(filepath)
    fullpath = os.path.join(filepath, filename)
    file = create_file(fullpath)
else:
    # The folder/file exists call function
    file = create_file(fullpath)

With this arrangement, CreateFile doesn't have a return line and the caller then gets nothing to do its function with. I think if it returns f, the file will close as soon as the function ends so I'm not sure what the caller gets. I will set up a test for it
(Nov-08-2022, 07:28 AM)JonWayn Wrote: [ -> ]With this arrangement, CreateFile doesn't have a return line and the caller then gets nothing to do its function with. I think if it returns f, the file will close as soon as the function ends so I'm not sure what the caller gets. I will set up a test for it
Yes,but the first code just open a diffent file object and return it this make no sense at all.
So i can write a more flexible apporch using a class and some gussing what this task shall do.
# court.py
import csv
import os

class Court:
    def __init__(self, filepath, filename, fullpath=''):
        self.filepath = filepath
        self.filename = filename
        self.fullpath = os.path.join(self.filepath, self.filename)

    def check_path(self):
        if not os.path.exists(self.fullpath):
            # Folder dos not exists,make it
            os.makedirs(self.filepath)
            self.fullpath = os.path.join(self.filepath, self.filename)
        else:
            # The folder/file exists
            self.fullpath 

    def create_file(self):
        header = ['Court', 'Location', 'Citation Number',
                  'Case Description', 'File Date', ]
        with open(self.fullpath, 'a', encoding='utf-8', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(header)

    def add_to_csv(self, data):
        with open(self.fullpath, mode='a', newline='') as cv:
            writer = csv.writer(cv, delimiter=',', quoting=csv.QUOTE_MINIMAL)
            writer.writerow(data)

    @property
    def read_csv(self):
        with open(self.fullpath, newline='') as csv_file:
            reader = csv.reader(csv_file)
            for row in reader:
                print(', '.join(row))
Using this class,no folder of file exsist when i start this.
λ ptpython -i court.py
>>> obj = Court(r'G:\div_code\test_cs1', 'data.csv')
>>> obj.check_path()
>>> obj.create_file()

# Now can read to see what have so far
>>> obj.read_csv
Court, Location, Citation Number, Case Description, File Date

# Add data to csv
>>> cort_data = ['Kent', 'Usa', '44455', 'Theft of car dealer', '8-11-22']
>>> obj.add_to_csv(cort_data)
>>> cort_data = ['Murder', 'Norway','9999', 'Bank robber', '5-1-22']
>>> obj.add_to_csv(cort_data)

# Read again to see what have now
>>> obj.read_csv
Court, Location, Citation Number, Case Description, File Date
Kent, Usa, 44455, Theft of car dealer, 8-11-22
Murder, Norway, 9999, Bank robber, 5-1-22
If look this hope see that this is more flexible,and is now easy to change if have more Court data(can just loop over and add).
Pages: 1 2