What does this mean: AttributeError: 'str' object has no attribute 'write' - python

When I go to run this code, I get the error above. I would understand if it was because one of my objects haven't been identified as strings but the error appears on the first file_name.write()
def save_itinerary(destination, length_of_stay, cost):
# Itinerary File Name
file_name = "itinerary.txt"
# Create a new file
itinerary_file = open('file_name', "a")
# Write trip information
file_name.write("Trip Itinerary")
file_name.write("--------------")
file_name.write("Destination: " + destination)
file_name.write("Length of stay: " + length_of_stay)
file_name.write("Cost: $" + format(cost, ",.2f"))
# Close the file
file_name.close()

You should be using itinerary_file.write and itinerary_file.close, not file_name.write and file_name.close.
Also, open(file_name, "a") and not open('file_name', "a"), unless you're trying to open a file named file_name instead of itinerary.txt.

An attribute error means that the object your trying to interact with, does not have the item inside it you're calling.
For instance
>>> a = 1
>>> a.append(2)
a is not a list, it does not have an append function, so trying to do this will cause an AttributError exception
when opening a file, best practice is usually to use the with context, which does some behind the scenes magic to make sure your file handle closes. The code is much neater, and makes things a bit easier to read.
def save_itinerary(destination, length_of_stay, cost):
# Itinerary File Name
file_name = "itinerary.txt"
# Create a new file
with open('file_name', "a") as fout:
# Write trip information
fout.write("Trip Itinerary")
fout.write("--------------")
fout.write("Destination: " + destination)
fout.write("Length of stay: " + length_of_stay)
fout.write("Cost: $" + format(cost, ",.2f"))

Related

Python (on replit.com) only allowing one instance of one function to run at a time

Here is some code I'm working on requiring string and the opening and closing of files.
#Importing required Packages---------------------------------------------
import string
# Importing Datasets-----------------------------------------------------
allNames = open("allNames.csv", "r")
onlyNames = open("onlyNames.csv", "r")
#=========Tasks==========================================================
# [1] findName(name, outputFile)-----------------------------------------
# Works ####
def findName(name, outputFile):
outfile = open(outputFile + ".csv", "w") # Output file
outfile.write("Artist \tSong \tYear\n") # Initial title lines
alreadyAdded = [] # List of lines already added to remove duplicates
for aline in allNames: # Looping through allNames.csv
fields = aline.split("\t") # Splitting elements of a line into a list
if fields[-1] == name + "\n": # Selecting lines with only the specified name (last element)
dataline = fields[0] + "\t" + fields[1] + "\t" + fields[3] # Each line in the .csv file
if dataline not in alreadyAdded: # Removing Duplicates
outfile.write(dataline + "\n") # Writing the file
alreadyAdded.append(dataline) # Adding lines already added
outfile.close()
# findName("Mary Anne", "mary anne")
# findName("Jack", "jack")
# findName("Mary", "mary")
# findName("Peter", "peter")
The code serves its intended purpose as I get an exported file. However, this only works for one function at a time, for example if I try to run both findName("Mary Anne", "mary anne") and findName("Jack", "jack") at the same time, the second instance of the function does not work. Moreover, all subsequent functions on the project file do not work unless I comment out this code.
Let me know what the issue is, thank you!

The file in python (AttributeError: 'str' object has no attribute 'append')

`File = input("Please enter the name for your txt. file: ")
fileName = (File + ".txt")
WRITE = "w"
APPEND = "a"
file = []
name = " "
while name != "DONE" :
name = input("Please enter the guest name (Enter DONE if there is no more names) : ").upper()
fileName.append(name)
fileName.remove("DONE")
print("The guests list in alphabetical order, and it will save in " + fileName + " :")
file.sort()
for U in file :
print(U)
file = open(fileName, mode = WRITE)
file.write(name)
file.close()
print("file written successfully.")
`
I am just practicing to write the file in Python, but something bad happened. Please help me. Thank you.
The code.
The error description.
Here are still some errors about this :
fileName.remove("DONE")
Still showing 'str' error.
THANK YOU
You try to append to string which is not correct in Python, instead try:
filename += 'name'
You're trying to build a list of names. Start with a list:
guests = []
and then append the values provided by your user:
while name is not "Done":
prompt = "Please input the name of the next guest, or 'Done'."
guests.append(input(prompt).upper())
then you can sort that list and write the values to the file. (which you seem to have a handle on)
Appending the guests' names to fileName, or concatenating them onto it, wouldn't make a lot of sense. You'd end up with something like "data.txtJOEBOBJANELINDA" which would do you no good at all.

Write to file python - Linebreak issue (\n)

I have a problem where the function just overwrites the line thats already there in a .txt file. The function is supposed to write a highscore to a file when the game quits (I have made a snake game by following a youtube tutorial). I can't quite figure out why it won't start on a new line, can anyone please explain the logic behind it, and how I fix it? I read somewhere that instead of "w" in f.open(), I should type "rb" or something. Since I'm kinda new to this "writing-to-file" thingy, I find it difficult.
Also, I want to sort the highscores from highest to lowest in the file (in other words, sort finalScore from highest to lowest). I have no idea how I should go on and code that, so I'd appreicate some help. You see, I want to print out the current highscores to the console (in order to make a scoreboad)
Heres the code:
import random
import time
name = "Andreas"
finalScore = random.randint(1,10)
def scoreToFile(finalScore):
#Has to be generated here, since we need the exact current time
currentTime = time.strftime("%c")
print("Sucsessfully logged score (finalScore) to highscores.txt")
f = open("highscores.txt", "w")
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
f.write(line + "\n")
f.close()
scoreToFile(finalScore)
Anyways, merry christmas my fellow python geeks! :D
1) one option is to open the file in append mode.
replace:
f = open("highscores.txt", "w")
with:
f = open("highscores.txt", "a")
2) another option is to replace this block,
f = open("highscores.txt", "w")
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
myfile.write(line + "\n")
f.close()
and use a with style
with open("highscores.txt", "a") as myfile:
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
myfile.write(line + "\n")
I prefer the second style as it is more safe and clean.
Mode w overwrites an existing file; mode 'a' appends to it. Also, the best way to handle a file is usually with the with statement, which ensures the closing on your behalf; so:
fileOutput = [(finalScore, "-", name, currentTime)]
with open("highscores.txt", "a") as f:
for t in fileOutput:
line = ' '.join(str(x) for x in t)
f.write(line + "\n")
For sorting, you need be able to extract the final score as a number from a line:
def minus_score(line):
return -int(line.split()[0])
then the total work will be done as:
def sorted_by_score():
with open("highscores.txt", "r") as f:
result = list(f)
return sorted(result, key=minus_score)
This will give you a list lines sorted in ascending order of score (the latter's the reason score is negating the number, though one might also choose to have it just return the number and reverse the sorting), for you to loop on and further process.
Added: so on the OP's request here's how the whole program might be (assuming the existence of a function that either plays a game and returns player name and final score, or else returns None when no more games are to be played and the program must exit).
import time
def play_game():
""" play a game and return name, finalscore;
return None to mean no more games, program finished.
THIS function you'd better code yourself!-)
"""
def scoreToFile(name, finalScore):
""" Add a name and score to the high-scores file. """
currentTime = time.strftime("%c")
fileOutput = finalScore, "-", name, currentTime
line = ' '.join(str(x) for x in fileOutput)
with open("highscores.txt", "a") as f:
f.write(line + "\n")
def minus_score(line):
""" just for sorting purposes, not called directly. """
return -int(line.split()[0])
def sorted_by_score():
""" return list of score lines sorted in descending order of score. """
with open("highscores.txt", "r") as f:
return sorted(f, key=minus_score)
def main():
while True:
game_result = play_game()
if game_result is None: break
scoreToFile(*game_result)
for line in sorted_by_score:
print(line.strip())
As others have mentioned, the problem is you're not opening the file in append mode, so it overwrites it every time rather than adding to it.
However, if you also want to keep the data in the file sorted, you do want to overwrite it each time, since the order of its contents will likely have been changed with the addition. To do that requires first reading it contents in, updating the data, and then writing it back out.
Here's a modified version of your function that does that. I also changed how the data in file is stored to what is known as Comma (or Character) Separated Values (CSV) format, because Python includes acsvmodule which makes it very easy to read, write, and do other things with such files.
import csv
import random
import time
highscores_filename = "highscores.txt"
HighScoresFirst = True # Determines sort order of data in file
def scoreToFile(name, finalScore):
currentTime = time.strftime("%c")
# Try reading scores from existing file.
try:
with open(highscores_filename, "r", newline='') as csvfile:
highscores = [row for row in csv.reader(csvfile, delimiter='-')]
except FileNotFoundError:
highscores = []
# Add this score to the end of the list.
highscores.append([str(finalScore), name, currentTime])
# Sort updated list by numeric score.
highscores.sort(key=lambda item: int(item[0]), reverse=HighScoresFirst)
# Create/rewrite highscores file from highscores list.
with open(highscores_filename, "w", newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='-')
writer.writerows(highscores)
print("successfully logged score (finalScore) to highscores.txt")
# Simulate using the function several times.
name = "Name"
for i in range(1, 4):
finalScore = random.randint(1,10)
scoreToFile(name + str(i), finalScore)
time.sleep(random.randint(1,3)) # Pause so time values will vary.

Why does my file show up blank in python?

I'm trying to get my python file to save numbers into a text file, but it always goes blank when I try it. I've done this many times before but it refuses to work this time.
openfile = 'example'
total = 0.5 #another example
totalstr = str(total)
file = open("%s.txt" % (openfile), "w")
file.write(totalstr)
file.close
"file" is a standard Python type. You want to rename things a bit. I'm also assuming "openfile" should be the string filename you want to use. Both answers so far are correct but putting them together gives:
my_file_name = "myfile"
total = 0.5
my_file_handle = open("%s.txt" %(my_file_name), "w")
my_file_handle.write(str(total))
my_file_handle.close()
file is a keyword in python. So,
print '%s' %(file)
prints
<type 'file'>
You should use:
openfile = 'file'
This works for me:
openfile = "file"
total = 0.5
totalstr = str(total)
file = open("%s.txt" % (openfile), "w")
file.write(totalstr)
file.close()
See if you can spot the changes.

Python script how can it do short

I have written a script on a python "icecast server", and I changed some strings in "/etc/icecast2/icecast.xml" like this:
import os,sys,re
def ices2():
changedir=open(pathh + "icecast3.xml", "w")
data=open("/etc/icecast2/icecast.xml").read()
changedir.write(re.sub("<source-password>hackme</source-password>","<source-password>123</source-password>" % x,data))
changedir.close()
ices2()
def ices1():
changedir1=open(pathh + "icecast2.xml", "w")
data=open(pathh + "icecast3.xml").read()
changedir1.write(re.sub("<relay-password>hackme</relay-password>", "<relay-password>123</relay-password>" % x,data))
changedir1.close()
os.remove(pathh + "icecast3.xml")
ices1()
def ices():
changedir2=open("/etc/icecast2/icecast.xml", "w")
data=open(pathh + "icecast2.xml").read()
changedir2.write(re.sub("<admin-password>hackme</admin-password>","<admin-password>123</admin-password>" % x,data))
changedir2.close()
os.remove(pathh + "icecast2.xml")
ices()
...but it's too long for the script. How can I shorten it? I need to do some changes in one file, open it to make changes and close it without any lost data. I know that it can be done in one function, but how to do it I don't know.
I need three changes in one function like this:
def ices():
changedir=open(pathh + "icecast3.xml", "w")
data=open("/etc/icecast2/icecast.xml").read()
changedir.write(re.sub("<source-password>hackme</source-password>","<source-password>123</source-password>",data))
changedir1.write(re.sub("<relay-password>hackme</relay-password>", "<relay-password>123</relay-password>",data))
changedir2.write(re.sub("<admin-password>hackme</admin-password>","<admin-password>123</admin-password>",data))
changedir.close()
i did it in one function and my script short than upper one. But it's wrong i need do it correctly
changedir=open(pathh + "icecast3.xml", "w")
data=open("/etc/icecast2/icecast.xml").read()
Here I create a new file "pathh + "icecast3.xml" (pathh-/home/user/Downloads), but I need to open file:
"/etc/icecast2/icecast.xml"
...read it and write changes to the same file.
All three functions do the same so you can join them into one. This is not complete solution but I think that you could go on from here on your own:
import os,sys,re
def ices(in_path, out_path, remove=False):
changedir = open(out_path, "w")
data = open(in_path, 'r')
changedir.write(re.sub("<source-password>hackme</source-password>","<source-password>123</source-password>" % x,data.read())) # this is wrong as well but I take it as an example
changedir.close()
data.close()
if remove:
os.remove(in_path)
You can call this function with:
ices(base_path + 'icecast2.xml', base_path + 'icecast3.xml', True)
Hints:
it's better to use os.path.join for creating the full paths (as opposed to string concatenation)
look at with statement and cosider using it for increased readability
EDIT (respecting the clarification in comment):
Sorry I missed the different strings in write. You can do it simply like this:
f = open(filename, 'r')
data = f.read()
f.close()
for tag in ['source', 'relay', 'admin']
sub_str = "<{tag_name}>%s</{tag_name}>".format(tag_name=tag+'-password')
data = re.sub(sub_str % 'hackme', sub_str % '123', data)
f = open(filename+'.new', 'w')
f.write(data)
f.close()

Categories

Resources