How do I permanently change the values of a text file? - python

im fairly new to handling files so im just confused
#pretend this is a text file, do not modify this part of the code.....
emps='''20120001;Tortor;Griffin;Manager;Admin;1000;5000
20120002;Sebastian;Jest;Assist. Manager;Admin;750;3000'''
f = open('empList.txt','w')
f.write(emps)
f.close()
#Code here
employees = []
while True:
print('''1 - Show Employees
2 - Increase Salary to employees
X - Exit
''')
choice = input('Enter your choice: ')
print()
if choice =='2':
with open('empList.txt', 'r') as f:
employees = f.read().splitlines()
for employee in employees:
emp_num, last, first, position, dept, salary, allowance = employee.split(';')
if position == 'Manager':
print(f'{emp_num} {last} {first} {float(salary)*2} {dept} {allowance} {position}')
else:
print(f'{emp_num} {last} {first} {float(salary)*1.5} {dept} {allowance} {position}')
print()
elif choice =='1':
with open('empList.txt', 'r') as f:
employees = f.read().splitlines()
for employee in employees:
emp_num, last, first, position, dept, salary, allowance = employee.split(';')
print(f'{emp_num} {last} {first} {float(salary)} {dept} {allowance} {position}')
print()
elif choice =='X':
break
my problem is whenever I input Choice 2 the changed values for salary is not permanent, so whenever I change the values by inputting Choice 2, it still shows the unchanged values, how do I fix this?
probably because I'm using a print statement but I'm in a stump as to what function I'm supposed to use here, I thought of using append but it would just make a copy of the data, what am I missing?
so something like this is the problem.
1 - Show Employees
2 - Increase Salary to employees
X - Exit
Enter your choice: 2
20120001 Tortor Griffin 2000.0 Admin 5000 Manager
20120002 Sebastian Jest 1125.0 Admin 3000 Assist. Manager
1 - Show Employees
2 - Increase Salary to employees
X - Exit
Enter your choice: 1
20120001 Tortor Griffin 1000.0 Admin 5000 Manager <---Value didn't change to 2000.0?
20120002 Sebastian Jest 750.0 Admin 3000 Assist. Manager <---Value didn't change to 1125.0?
1 - Show Employees
2 - Increase Salary to employees
X - Exit

First thing is you are opening the file with 'r', which is in read-only mode. You need to change it to 'w', like: with open('empList.txt', 'w').
Second thing is you are not writing anything to the file, you are just printing it. You miss f.write(...) in the choices.

You can create a copy of the new data and then write it back to the file using write() function something like below. Note that the code is not tested but the approach should help you figure out the solution.
if choice =='2':
with open('empList.txt', 'r') as f:
employees = f.read().splitlines()
# create a new list to store modified employee data
modified_employees = []
for employee in employees:
emp_num, last, first, position, dept, salary, allowance = employee.split(';')
if position == 'Manager':
# Append current employee record with modified salary to the new list
modified_employees.append("{};{};{};{};{};{};{}".format(emp_num, last, first, position, dept, salary*2, allowance))
print(f'{emp_num} {last} {first} {float(salary)*2} {dept} {allowance} {position}')
else:
# Append current employee record with modified salary to the new list
modified_employees.append("{};{};{};{};{};{};{}".format(emp_num, last, first, position, dept, salary*1.5, allowance))
print(f'{emp_num} {last} {first} {float(salary)*1.5} {dept} {allowance} {position}')
# Write the new list back to file. This will overwrite previous content and keeps the fresh
with open('empList.txt', 'w') as f:
for each_record in modified_employees:
f.write("{}\n".format(each_record))

Related

Add \n to the last element of a list, in a list of lists

So I have an external file where each line has a task formatted like this:
User, Title of task, Description of task, Date assigned, Due date, Completed (Yes/No)
I have created a list of lists where within the main list are lists of the line above essentially where each element is separated from the ", ".
So it looks like this:
[['User', 'Title of task', 'Description of task', 'Date assigned', 'Due Date', 'Completed (Yes/No)']]
I am trying to change the last element of the last list to include "\n" at the end.
Here is the code I implemented:
with open('tasks.txt', 'w') as f2:
count = 0
for i in list_of_tasks:
count += 1
if count == len(list_of_tasks):
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
f2.write(", ".join(i))
else:
f2.write(", ".join(i))
This is the error I get:
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
~~~~~~~~~~~~~^^^
TypeError: list indices must be integers or slices, not list
Ultimately what I'm trying to achieve is to edit parts of each line in this external file. The initial problem I have is the spacing after writing to the file gets messed up hence I'm trying to figure out how to add \n to the last element in the final list in this list of lists.
if it helps here's the full function:
def view_mine(username):
# opens tasks.txt as read only and assigns it as a variable named f1
with open('tasks.txt', 'r') as f1:
x = 1
list_of_tasks= []
other_tasks = []
for line in f1:
line3_split = line.split(', ')
if line3_split[0] == username:
user_format = f"""
Task {x}: {line3_split[1]}
Assigned to: {line3_split[0]}
Date assigned: {line3_split[3]}
Due date: {line3_split[4]}
Task complete? {line3_split[5]}
Task description:
{line3_split[2]}
"""
print(user_format)
x += 1
list_of_tasks.append(line3_split)
else:
other_tasks.append(line3_split)
selection = int(input(f"Which task do you want to select (1-{x-1}) or enter '-1' to return to main menu? ")) -1
if selection == -2:
return
else:
mark_or_edit = int(input(f"To mark as complete enter '1'. To edit the task enter '2'."))
if mark_or_edit == 1:
if list_of_tasks[selection][-1] == "No":
list_of_tasks[selection][-1] = "Yes\n"
elif list_of_tasks[selection][-1] == "No\n":
list_of_tasks[selection][-1] = "Yes\n"
elif mark_or_edit == 2:
user_or_date = int(input("To edit user assigned enter '1'. To edit due date enter '2'. "))
if user_or_date == 1:
user_check = input("Which user do you want to assign this task to? ")
existing_names_list = []
with open('user.txt', 'r') as f:
for line in f:
existing_names = line.split(', ')
existing_names_list.append(existing_names[0])
if user_check in existing_names_list:
list_of_tasks[selection][0] = user_check
else:
print("User does not exist.")
elif user_or_date == 2:
new_date = input("Enter the new due date (XX XXX XXXX): ")
list_of_tasks[selection][4] = new_date
with open('tasks.txt', 'w') as f2:
count = 0
for I in list_of_tasks:
count += 1
if count == len(list_of_tasks):
list_of_tasks[i][-1] = str(f"{list_of_tasks[i][-1]}\n")
f2.write(", ".join(i))
else:
f2.write(", ".join(i))
for i in other_tasks:
f2.write(", ".join(i))
return
The problem is in:
for i in list_of_tasks
In this situation i is a string and you are trying to use it as index in your list.
I am not sure what you are trying to accomplish exactly, but I think your code has some logical inaccuracies. I hope the following code gets the job done:
with open('tasks.txt', 'w') as f2:
count = 0
for sub_list in list_of_tasks:
for i in range(len(sub_list)):
if i == len(sub_list) - 1:
temp = sub_list[i] + '\n'
f2.write(temp)
else:
f2.write(sub_list[i] + ', ')
The output of the above code for the list you provided is:
User, Title of task, Description of task, Date assigned, Due Date, Completed (Yes/No)
with '\n' included in the end, even if it is not obvious.
It seems that you have a list of lists, so a 2D array, in which every element is a string. So you have to loop once for the first dimension (so for each list) and then for the second dimension(so for each string in list). Having every string each time, you are able to create the sentence you are trying to.

Having trouble exporting user input to txt file in Python

So long story short, I have been working on a Python program and I have been trying to get what the user inputs into the program to a txt file - I received some help online overall, but a bit stumped here.. Need it to include index, make, model, color, year and mileage of the vehicles that have been input (basically what is visible in the output when user hits "4" at main menu). The idea is when user hits "6" , that list/ data will be exported to txt file named "Vehicle Inventory" and then Exit the application. The issue is definitely around end of code at elif ch == 6: ... Any assistance or resolution on this would be appreciated !! Here is what I have so far:
# automobile class
class automobile:
# constructor
def __init__(self, make="", model="", color="", year=2018, mileage=0):
self.make = make
self.model = model
self.color = color
self.year = year
self.mileage = mileage
# setter methods
def set_make(self, make):
self.make = make
def set_model(self, model):
self.model = model
def set_color(self, color):
self.color = color
def set_year(self, year):
self.year = year
def set_mileage(self, mileage):
self.mileage = mileage
# getter methods
def get_make(self):
return self.make
def get_model(self):
return self.model
def get_color(self):
return self.color
def get_year(self):
return self.year
def get_mileage(self):
return self.mileage
# end of automobile class
# method to add a new vehicle to the inventory
def add_vehicle(v_list):
make = input("Enter make: ")
model = input("Enter model: ")
color = input("Enter color: ")
year = int(input("Enter year: "))
mileage = int(input("Enter mileage: "))
v = automobile(make, model, color, year, mileage)
v_list.append(v)
print("*** VEHICLE ADDED SUCCESSFULLY...")
# method to remove a vehicle from the inventory
def remove_vehicle(v_list):
index = int(input("Enter the index # of vehicle you would like to remove: "))
if index >= 0 and index < len(v_list):
make = v_list[index].get_make()
model = v_list[index].get_model()
v_list.pop(index)
print(make, model, "HAS BEEN REMOVED FROM INVENTORY !")
else:
print("*** INVALID INDEX #... PLEASE TRY AGAIN")
# method to update a vehicle info in the inventory
def update_vehicle(v_list):
index = int(input("Enter the index # of vehicle you would like to update: "))
if index >= 0 and index < len(v_list):
make = input("Enter new make: ")
model = input("Enter new model: ")
color = input("Enter new color: ")
year = int(input("Enter new year: "))
mileage = int(input("Enter new mileage: "))
v_list[index].set_make(make)
v_list[index].set_model(model)
v_list[index].set_color(color)
v_list[index].set_year(year)
v_list[index].set_mileage(mileage)
print("*** UPDATED SUCCESSFULLY !")
else:
print("*** INVALID INDEX #... PLEASE TRY AGAIN")
# method to print all vehicle details in proper formatted order
def display_vehicles(v_list):
print('{:10} {:10} {:10} {:10} {:10} {:10}'.format('INDEX #', 'MAKE', 'MODEL', 'COLOR', 'YEAR', 'MILEAGE'))
for i in range(len(v_list)):
v = v_list[i]
print('{:10} {:10} {:10} {:10} {:10} {:10}'.format(str(i), v.get_make(), v.get_model(), v.get_color(), str(v.get_year()), str(v.get_mileage())))
v_list = [] # initial list
# looping infinitely
while True:
# showing menu
print("1. Add a vehicle")
print("2. Remove a vehicle")
print("3. Update a vehicle")
print("4. Display all vehicle inventory")
print("5. Exit")
print("6. Export to 'Vehicle Inventory' txt file and Exit")
# getting choice
ch = int(input("*** PLEASE CHOOSE AN OPTION: "))
# performing actions based on choice
if ch == 1:
add_vehicle(v_list)
elif ch == 2:
remove_vehicle(v_list)
elif ch == 3:
update_vehicle(v_list)
elif ch == 4:
display_vehicles(v_list)
elif ch == 5:
break;
elif ch == 6:
with open('Vehicle Inventory.txt', 'w') as filehandle:
for display_vehicles in v_list:
filehandle.write("%s\n" % display_vehicles)
break;
else:
print("*** INVALID OPTION... PLEASE TRY AGAIN")
Executing your code, the txt file contains lines such as
<__main__.automobile object at 0x0000017F5E7017C0>.
The problem is that at line filehandle.write("%s\n" % display_vehicles) pass an object reference as data to be written to the file. As far as I know, there is no ready-made function that allows you to pass a file an object reference and have the data auto-extracted from it. If you really want to use a txt file, you can do something like this:
with open('Vehicle Inventory.txt', 'w') as filehandle:
for display_vehicles in v_list:
filehandle.write("make: {}, model: {}, color: {}, year: {}, mileage:{} \n".format(display_vehicles.get_make(),display_vehicles.get_model(),display_vehicles.get_color(),display_vehicles.get_year(),display_vehicles.get_mileage()))
Output
make: car, model: a, color: red, year: 2020, mileage:20
make: car2, model: b, color: black, year: 10, mileage: 10
A brief explanation of Format.
Format allows you to insert values into a string using a style based on placeholders. {} correspond to anonymous placeholders: this means that the value that goes in that position depends on the order used inside .format(value1, value2, ...).
Alternatively, you can use named placeholders such as:
"my car is {color} and i bought it in {year}".format(color= "red", year= 2010)
About the txt file
Personally I would not use a txt file, especially since loading data from this type of file can be quite annoying in cases where you are only interested in a few rows or a certain value of each row (e.g.: all red cars). I don't know if the txt file is mandatory for you, so I won't provide any detailed info on the following alternative methods. In any case, you should know that there are other types of files that are widely used for storing information.
Json. The data are stored into a dictionary, i.e. a set of key-value pairs. Reading and writing files is trivial thanks to the json module
Csv. This is very similar to a txt but has a more structured form, as if it were a table. Each row corresponds to a record, each record consists of columns. Thanks to pandas, it is easy to use csv to extract subsets of data based on the value contained in the records or the row index. The file structure also allows you to quickly create graphs and export data to Excel.
Pickle. If you don't even care about human-friendly representation but just want to save the data permanently to a file, you could try pickle

Why does replace not work for this substring?

I'm completely new to Python so I apologize in advance for the bad code. I am trying to replace the sub-string of strings in a list, but the list returned is the same. In the code, there is a list of accounts and another list of transactions given by the user, I am supposed to check whether the command is add or sub to either add to balance or subtract from it. Here is the format for both lists:
F1:
ACCOUNT NUMBER | PIN CODE | BALANCE
F2:
COMMAND | AMOUNT | ACCOUNT NUMBER | PIN CODE
And here is the code I'm working with:
import sys
F1 = sys.argv[1]
F2 = sys.argv[2]
def file_reader(filePath):
file = open(filePath, 'r')
data = file.read()
file.close()
return data
def splitter(str):
return str.split()
def joiner(list):
return '\n'.join(list)
def file_writer(filePath, str):
file = open(filePath, 'w')
file.write(str)
def make_transaction(accounts, transactions):
for i in range(len(transactions)):
# Check account number & pin
if accounts[i][0:4] == transactions[i][9:13]:
if accounts[i][5:9] == transactions[i][-4:]:
# Check whether the user wants to add or subtract from balance
if 'add' in transactions[i]:
balance = int(accounts[i][10:])
transaction = int(transactions[i][4:8])
balance += transaction
balanceStr = str(balance)
accounts[i].replace(accounts[i][10:], balanceStr)
elif 'sub' in transactions[i]:
balance = int(accounts[i][10:])
transaction = int(transactions[i][4:8])
if balance > transaction:
balance -= transaction
balanceStr = str(balance)
accounts[i].replace(accounts[i][10:], balanceStr)
return accounts
file1 = fileReader(F1)
file1Data = splitter(file1)
file2 = fileReader(F2)
file2Data = splitter(file2)
print(file1Data)
print(file2Data)
print(makeTransaction(file1Data, file2Data))
This is the output:
Program Failed for Input: /tmp/a1 /tmp/tx
Expected Output:
Your Program Output: ['1000|1234|10000', '1020|2222|0', '3000|3344|1000', '2020|1234|90000']
['add|1000|1000|1234', 'sub|1000|1020|2222', 'sub|1000|3000|3344']
['1000|1234|10000', '1020|2222|0', '3000|3344|1000', '2020|1234|90000']
Any help would be appreciated. Thank you.
.replace is risky use case for what you are trying to solve. It is using pattern matching to do the change and in case your substring, i.e. balance[10:] would accidentally match with balance[0:5] you would silently get very unpredictable results.
Instead, I would suggest you replace
accounts[i].replace(accounts[i][10:], balanceStr)
with
accounts[i] = accounts[i][0:9] + balanceStr
On an extra note, assuming that your input data is split by |, you should create data holders for your input data instead of working with the strings as the strings are volatile and your code could start acting unpredictably if your customer performed a very large transaction.
I would instead do something along the lines of account_number, pin_code, balance = '1000|1234|10000'.split('|') and load the data into a list where each row would represent one account or one transaction.
This should be completely rewritten:
def make_transaction(accounts, transactions):
for i in range(len(transactions)):
# Check account number & pin
if accounts[i][0:4] == transactions[i][9:13]:
if accounts[i][5:9] == transactions[i][-4:]:
# Check whether the user wants to add or subtract from balance
if 'add' in transactions[i]:
balance = int(accounts[i][10:])
transaction = int(transactions[i][4:8])
balance += transaction
balanceStr = str(balance)
accounts[i].replace(accounts[i][10:], balanceStr)
elif 'sub' in transactions[i]:
balance = int(accounts[i][10:])
transaction = int(transactions[i][4:8])
if balance > transaction:
balance -= transaction
balanceStr = str(balance)
accounts[i].replace(accounts[i][10:], balanceStr)
return accounts
for example, I'd rather do this:
def make_transaction(accounts, transactions) :
for a,t in zip(accounts, transactions) :
a_num, a_pin, a_balance = a.split('|')
t_command, t_amount, t_num, t_pin = t.split('|')
if a_num == t_num and a_pin == t_pin :
if t_command == 'add' :
# do your stuff
elif t_command == 'sub' :
# do something else
and so on... working on string with indices is very very wrong.

Getting python homework dictionary program to save and exit properly

Working on a homework problem. Have almost all of the code working but for some reason cant seem to get my program to save and exit properly.
here is the prompt given.
You should create a program that manages a tab-separated text file containing employees travel expenses. There are 4 and only 4 employees who travel for the company: alice, bob, carl, and diane. Each record in the data file will contain an employee name, a destination city, miles traveled, and gallons used.
For full credit:
Your program should properly read and store the given data to and from the tab-separated data file. That is, I should be able to use your program with my data file without error.
When the data is read into your program it should be organized as a list of dictionaries, where each dictionary is a row in the file, using these dictionary keys: name, city, miles, gallons.
You need to add functionality to display the user's name, total miles traveled, total gallons used, average mpg, and the expense of the total miles at 75 cents per mile. This should work for any of the 4 proper user names you enter.
You do not need to do any data validation unless just want to.
If and only if your program runs exactly like it should, I will add a 10 point bonus if, rather than using concatenation, you properly use the python CSV module to read and write the data to and from the file, converting the tab-separated data to a dictionary and vice versa.
You need to use the base code provided by the lecture notes, more or less. All 4 menu options should work.
Use formatting to have everything line up in neat columns for display option 1.
My problem is that I cannot get the 4th option "Save and exit" to function properly.
def read_file(travels):
salesperson_list = []
with open("travels.txt", 'r') as infile:
for line in infile.readlines():
line = line.strip().split('\t')
d = {}
d['name'] = line[0]
d['city'] = line[1]
d['miles'] = eval(line[2])
d['gallons'] = eval(line[3])
salesperson_list.append(d)
return salesperson_list
def display_all_data(data):
print('{0:<8}{1:<15}{2:<8}{3:<8}'.format('Name', 'City', 'Miles', 'Gallons'))
for row in data:
print('{0:<8}{1:<15}{2:^8}{3:^8}'.format(row.get('name'), row.get('city'), \
row.get('miles'), row.get('gallons')))
def calculate_user_data(data):
name = input('Enter user name: ').lower()
total_miles = sum([row.get('miles') for row in data if row.get('name') == name])
total_gallons = sum([row.get('gallons') for row in data if row.get('name') == name])
cities = [row.get('city') for row in data if row.get('name') == name]
mpg = total_miles/total_gallons
owed = mpg*0.75
print('Total miles travelled: {0}'.format(total_miles))
print('Total gallons used: {0}'.format(total_gallons))
print('mpg = ',mpg)
print('expense = $', owed, 'at 75 cents per mile')
def add_a_trip(data):
name = input('Input name: ').lower()
city = input('Input city travelled: ').lower()
miles = eval(input('Enter miles travelled: '))
gallons = eval(input('Enter gallons used: '))
d = {}
d['name'] = name
d['city'] = city
d['miles'] = miles
d['gallons'] = gallons
data.append(d)
print('Data added successfully')
def save_And_exit(data):
with open('F:\\travels.txt','w') as outfile:
for row in data:
outfile.write(row.get('name')+'\t'+row.get('city')+'\t'+\
str(row.get('miles'))+'\t'+str(row.get('gallons'))+'\n')
print('Saved to file')
def menu(salesperson_list):
print('Menu options. Choose 1, 2, 3, or 4')
print('[1] Display all trip data')
print('[2] Calculate user data')
print('[3] Add a trip')
print('[4] Save an exit')
while True:
choice = input('Enter choice --> ')
if choice == '1':
display_all_data(salesperson_list)
elif choice == '2':
calculate_user_data(salesperson_list)
elif choice == '3':
add_a_trip(salesperson_list)
elif choice == '4':
save_And_exit(salesperson_list)
print('Bye')
break
else:
print('Invalid selection')
def main():
salesperson_list = read_file('F:\\travels.txt')
menu(salesperson_list)
main()
I just need my program to save and exit properly with no global variables

Matching user input to file records in Python

i'm making a program that will ask a user to enter their student ID and it will display the student information such as student ID and their student name . i does this first by asking the user to enter their id and it will then read a .txt file and check if the student id is a matched then it will print out the content of my .txt file information of the specific student that the user is looking for.
this is my content of the file
201707001 Michael_Tan
201707002 Richard_Lee_Wai_Yong
201707003 Jean_Yip
201707004 Mark_Lee
201707005 Linda_Wong
201707006 Karen_Tan
201707007 James_Bond
201707008 Sandra_Smith
201707009 Paul_Garcia
201707010 Donald_Lim
this is my source code
# user can find out the student info
userInput = input("Please enter a student ID: ")
# read the students file
with open('C:\\Users\\jaspe\\Desktop\\PADS Assignment\\Student.txt') as f:
studentFile = f.readlines()
for student in studentFile:
stdId, stdName = student.strip().split(" ",1)
# check if the student exist
matched = True
while matched:
if userInput == stdId:
print("True")
else:
print("False")
matched = False
break
but the output i get is false even though i type the exact studentID
You should perform your checks as you read your file. Otherwise, you are splitting and obtaining your information, but this data is lost in the subsequent iteration. Try this:
with open('C:\\Users\\jaspe\\Desktop\\PADS Assignment\\Student.txt') as f:
studentFile = f.readlines()
for student in studentFile:
stdId, stdName = student.strip().split()
if userInput == stdId:
print(stdName)
break
Better still, for large files, iterate line-wise. Do not use f.readlines because it loads all your data into memory.
with open('C:\\Users\\jaspe\\Desktop\\PADS Assignment\\Student.txt') as f:
for line in f:
stdId, stdName = line.strip().split()
if userInput == stdId:
print(stdName)
break
As it stands your code loops through every ID and name and assigns each into the stdId and stdName, but that loop exits before you check for a match... Because of that it only holds the last value stored in those variables by the loop. You need the check in the loop, as so
# user can find out the student info
userInput = input("Please enter a student ID: ")
# read the students file
with open('C:\\Users\\jaspe\\Desktop\\PADS Assignment\\Student.txt') as f:
studentFile = f.readlines()
for student in studentFile:
stdId, stdName = student.strip().split(" ",1)
# check for a match here, break the loop if a match is found
Use raw_input instead of input.
You almost never want to use input, because it does evaluation. In this case, typing in an exact integer gives you an integer, while the file gives you a string, so it won't match.
You have other minor / major issues in the code.
If the loop is entered with userInput == stdId you will loop forever printing True.
You never actually search through the student ids, you just check the last one set in your previous loop
(For this I would recommend using a dictionary if you plan to do multiple user queries, or just look as you read the lines of the file for a simple script)

Categories

Resources