Python Forum
Writing to file ends incorrectly
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Writing to file ends incorrectly
#1
Hi,

An external txt file has 2 numbers in it (default). I'm asking a user to input 2 new numbers in my script. These then get written to the text file. The code then reads the default 2 numbers which were already in there, overwrites them, and then prints new numbers in there.

The code is supposed to go until the while loop is false. At the end of the function
def file_access(a,b):
, I have:

choice = input("Press any key to continue, or type 'n' to end: ")

        if choice != -1:
            print()
        else:
            this_var = choice

        return choice
I'm trying to make it if the user enters anything but 1, then
file_access(a,b)
will return this entry to the while loop, and thus ends it. However, even pressing 1 ends the code.

There's likely some issue with calling
file_access(num1, num2) 
inside
input_nums()
. I also tried setting
this_var
to some terminal character at the end, and I thought that would work since it's a global variable, but that didn't work either.

Where am I going wrong?

def input_nums():
    num1 = input("enter num1: ")  #data type of input MUST be a string, in order to write to a file
    num2 = input("enter num2: ")
    file_access(num1, num2)            #this passes parameters, num1 and num2 into arguements of func 'file access'
                                       # this is VERY impt, as it allows you to return 2 vars into another function
def file_access(a,b):

    #read what's in file currently, print results
        print("\nPreviously in file:")
        file = open("demo.txt", 'r')  # (which file to open, mode)  Mode means what you're doing to the file (e.g. write or read)
                                      # 'w' = write to file, 'r' = read file
        content = file.read() #after reading file, it must store the content, e.g. in a variable, 'content'
        print(content)  # print what was read
        file.close()    # after opening a file, you always have to close it

    #write to file
        print("\nNew numbers in file:")
        file = open("demo.txt", "w")

        file.write("Number 1 entered = ")  # writes text to file
        file.write(a)  # writes text to file, MUST pass a string
        file.write("\n")

        file.write("Number 2 entered = ")  # writes text to file
        file.write(b)  # writes text to file
        file.write("\n")

        file.close()  # closes file

    #read file
        file = open("demo.txt", "r")  # opens file, tells program it will write to it
        content = file.read()  # reads file, returns info to var 'content'
        print(content)  # prints var content
        file.close()

        choice = input("Press '1' to continue, or any other key to end: ")

        if choice == 1:
            print() #do nothing, just skip a line
        else:
            this_var = choice # this will end code

        return choice

this_var = 1 # default condition, so while loop will always run

while this_var == 1:
    this_var = input_nums()
    print("this_var = ",this_var)
Reply
#2
The thing that I found is that in
def input_nums():
    num1 = input("enter num1: ")  #data type of input MUST be a string, in order to write to a file
    num2 = input("enter num2: ")
    file_access(num1, num2)     
You return nothing to the program. Try something like:
f = file_access(num1, num2) 
return f
Reply
#3
There are no numbers anywhere in this program. The function input_nums() inputs two strings. You could enter "sunny" for num1 and "day" for num2 and it would work exactly the same as it does now.

this_var is not a global variable. There is a variable named "this_var" defined in the module scope and another variable named "this_var" defined in the scope for function "file_access". They are not the same variable. They only have the same name.

I wish the term "global variable" would go away. There is no such thing in Python. You have variables defined in the local scope, the scope of the local scope, the scope of that scope and on an on until you get to the module (file) scope. You also have variables defined in the built-ins. There is no "global" scope for variables.

The "global" keyword does not make a magical global variable. "global" tells Python to look for a variable defined outside the local scope instead of creating a new local variable. Assignment is how you make variables in Python, and when "this_var = choice" is executed in file_access() it creates a local variable (in the file_access scope)with the name "this_var". If you want to use the "this_var" that is defined in the module scope you need to tell Python by using "global this_var" at the start of your file_access() function.

Your design is bad. Each function should have a well designed task. input_num() should not be reading and writing files. file_access() does what exactly? It certainly shouldn't be asking if the user wants to continue. I got in the habit of writing docstrings before I write my code. Not only does this ensure that I write a docstring for each function, but it helps me design better functions. If I can't write a short description of what he function does, it is not really a function.

This is your program with three (fairly) well defined functions.
def input_nums():
    '''Get two integers from the user'''
    try:
        num1 = int(input('enter num1: '))
        num2 = int(input('enter num1: '))
        return (num1, num2)
    except ValueError:
        print('Please enter integer numbers')
    return None

def print_file(filename):
    '''Print contents of filename to console'''
    try:
        # Do not assume file open always works
        with open(filename, 'r') as file:
            # Let a context manager close the file for you
            print(file.read())
    except Exception as ex:
        print('Error reading file', filename)
        print(ex)

def write_file(filename, num1, num2):
    '''Write num1 and num2 to filename'''
    try:
        # Do not assume fil open always works
        with open(filename, 'w') as file:
            # Let a context manager close the file for you
            file.write(f'Number 1 entered {num1}\n')
            file.write(f'Number 2 entered {num2}\n')
    except Exception as ex:
        print('Error writing file', filename)
        print(ex)

filename = 'test.txt'
while True:
    print('\nPreviously in file:')
    print_file(filename)

    numbers = input_nums()
    if numbers is None:
        continue
    write_file(filename, *numbers)
    
    print('\nNew file:')
    print_file(filename)

    if input("Press '1' to continue, or any other key to end: ") != '1':
        break
The code and the logic are much cleaner when everything has a well defined purpose. Notice we don't even need a global variable because the continue logic is no longer hidden behind a couple of functions,

I also wrapped exception handlers around the code that is likely to fail (input and file open/create). And I used context managers (with) to handle closing files when I no longer need them.
Reply
#4
def input_nums():
    '''Get two integers from the user'''
    try:
        num1 = int(input('enter num1: '))
        num2 = int(input('enter num1: '))
I see what you've done here, and it's interesting, because I didn't realize that num1 and num2 could used outside of the function without them being returned, then passed into:
def write_file(filename, num1, num2):
That's the confusion I have with local scope vars and 'global' vars. But apparently I'm mistaken here.


What I don't really understand is what you've done with numbers and *numbers here:
numbers = input_nums()
    if numbers is None:
        continue
    write_file(filename, *numbers)
It appears you're using a pointer or reference, but I'm unsure.
Reply
#5
(Jan-06-2021, 04:53 PM)project_science Wrote:
def input_nums():
    '''Get two integers from the user'''
    try:
        num1 = int(input('enter num1: '))
        num2 = int(input('enter num1: '))
I see what you've done here, and it's interesting, because I didn't realize that num1 and num2 could used outside of the function without them being returned

But they are returned. The very next line returns them.


Quote:What I don't really understand is what you've done with numbers and *numbers here:
numbers = input_nums()
    if numbers is None:
        continue
    write_file(filename, *numbers)
It appears you're using a pointer or reference, but I'm unsure.

The * operator unpacks collections. It's not similar to a pointer.

Say you have a tuple: t = (1, 2, 3). If you call a function as f(t), the function gets the tuple as a single argument. If you instead unpack it as f(*t), the function gets the contents of the tuple, not the tuple itself. In this particular case, it would get 3 int arguments.

In the code above, input_nums returns (num1, num2). This is assigned to numbers on line 39. So when write_file is called, it's the same as write_file(filenname, numbers[0], numbers[1]), where those components are the input numbers.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Writing string to file results in one character per line RB76SFJPsJJDu3bMnwYM 4 1,368 Sep-27-2022, 01:38 PM
Last Post: buran
  Writing to json file ebolisa 1 996 Jul-17-2022, 04:51 PM
Last Post: deanhystad
  pywin32: Outlook connection ends with 'operation aborted' on one machine tstone 0 2,375 May-03-2022, 04:29 AM
Last Post: tstone
  Writing to External File DaveG 9 2,484 Mar-30-2022, 06:25 AM
Last Post: bowlofred
  Regex: a string does not starts and ends with the same character Melcu54 5 2,416 Jul-04-2021, 07:51 PM
Last Post: Melcu54
  threadlocals are garbage collected before thread ends akv1597 0 1,797 Mar-09-2021, 12:13 PM
Last Post: akv1597
  Running a few lines of code as soon as my timer ends nethatar 3 2,398 Feb-26-2021, 01:02 PM
Last Post: jefsummers
  Writing unit test results into a text file ateestructural 3 4,738 Nov-15-2020, 05:41 PM
Last Post: ateestructural
  Writing to file in a specific folder evapa8f 5 3,412 Nov-13-2020, 10:10 PM
Last Post: deanhystad
  Keep Application running after Python script ends PEGylated_User 0 1,975 Nov-12-2020, 03:27 PM
Last Post: PEGylated_User

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020