Im analyzing a text for word frequency and I am getting this error message after it is done:
'str' object has no attribute 'close'
I've used the close() method before so I dont know what to do.
Here is the code:
def main():
text=open("catinhat.txt").read()
text=text.lower()
for ch in '!"$%&()*+,-./:;<=>=?#[\\]^_{|}~':
text=text.replace(ch,"")
words=text.split()
d={}
count=0
for w in words:
count+=1
d[w]=d.get(w,0)+1
d["#"]=count
print(d)
text.close()
main()
You didn't save a reference to the file handle. You opened the file, read its contents, and saved the resulting string. There's no file handle to close. The best way to avoid this is to use the with context manager:
def main():
with open("catinhat.txt") as f:
text=f.read()
...
This will close the file automatically after the with block ends, without an explicit f.close().
That is because your variable text has a type of string (as you are reading contests from a file).
Let me show you the exact example:
>>> t = open("test.txt").read()
#t contains now 'asdfasdfasdfEND' <- content of test.txt file
>>> type(t)
<class 'str'>
>>> t.close()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'close'
If you use an auxiliary variable for the open() function (which returns a _io.TextIOWrapper), you can close it:
>>> f = open("test.txt")
>>> t = f.read() # t contains the text from test.txt and f is still a _io.TextIOWrapper, which has a close() method
>>> type(f)
<class '_io.TextIOWrapper'>
>>> f.close() # therefore I can close it here
>>>
text=open("catinhat.txt").read()
text is a str since that is what .read() returns. It does not have a close method. A file object would have a close method, but you didn't assign the file you opened to a name thus you can no longer refer to it to close it.
I recommend using a with statement to manage the file:
with open("catinhat.txt") as f:
text = f.read()
...
The with statement will close the file whether the block finishes successfully or an exception is raised.
Related
What I Want
I have written a code that opens a file (currentcode) gets it's text finds it in another file (text.txt) and replaces currentcode with a new int.
My Code
import os
currentcode = open('currentcode.txt','r+')
code = currentcode.read()
print('Choose File: ')
print('1: File One > ')
file = input('Enter Number Of File: ')
file = 'C:/text.txt'
old_text = code
new_text = str(int(code) + 1)
print('Opened File')
f1 = open(file, 'r')
f2 = open(file, 'w')
f2.write(replace(old_text, new_text))
currentcode.write(new_text)
f1.close()
f2.close()
Output After Running
When I Run This Code I Get:
Choose File:
1: File One >
Enter Number Of File: 1
Opened File
Traceback (most recent call last):
File "C:\Users\DanielandZoe\Desktop\scripys\Replace.py", line 18, in <module>
f2.write(replace(old_text, new_text))
NameError: name 'replace' is not defined
NameError: name 'replace' is not defined
That means python couldn't find a module, class or function called 'replace'.
If you want to replace text on a file, you need to get its contents as a string, not as a file-like object (like you're doing now), then you replace the contents using the replace method on your string and finally, write the contents to the desired file.
string.replace() is a method for strings:
https://docs.python.org/2/library/string.html#string.replace
what is in f2? Not a string. You should read the lines of the file.
when I try to write data to a file I get no errors but when I try to read it back nothing is in the file. What am I doing wrong?
test = open('/Users/MYUSER/Desktop/test.txt', 'r+')
test.write("RANDOME STRING\n")
test.read()
''
You need to move the file pointer to the start of the file using file.seek before calling .read(). When you write something to a file, the file pointer moves to the end of file, that's why calling .read() on the file object was returning an empty string.
Demo:
>>> test = open('abc1', 'r+')
>>> test.write('foo')
>>> test.read()
''
>>> test.seek(0)
>>> test.read()
'foo'
i have been working on a python tutorial and have come across a problem which i simply cannot work out. google has not turned up anything specific and after a few hours away and much trial and error i still cannot work it out.
anyway, the below code is a simplified version of the tutorial. it works fine and prints out that my file is 17 bytes long:
from sys import argv
from os.path import exists
script, file1 = argv
file_open = open(file1)
file_read = file_open.read()
print "the file is %s bytes long" % len(file_read)
then the tutorial asks to merge lines 6 and 7 into a single line. if i do it like this it works:
from sys import argv
from os.path import exists
script, file1 = argv
file_read = open(file1).read()
print "the file is %s bytes long" % len(file_read)
but, if i do it like like this then i get an error message which says TypeError: object of type 'file' has no len():
from sys import argv
from os.path import exists
script, file1 = argv
file_read = open(file1, "r+")
print "the file is %s bytes long" % len(file_read)
my problem is i cannot work out why that error message is occurring when i am adding the "r+" to make sure the open file is read. ( although, is it true that read is default anyway so maybe even adding the r+ is unnecessary )
any help would be much appreciated. many thanks :)
I think you forgot the .read() in:
file_read = open(file1, "r+")
so file_read is a file object. Try with:
file_read = open(file1, "r+").read()
and it will return a string as expected.
Regardless of whether you open it in r mode, r+ mode, or any other mode, opening a file with the open built-in returns a file object:
>>> open('test.txt', 'r+')
<open file 'test.txt', mode 'r+' at 0x013D9910>
>>> type(open('test.txt', 'r+'))
<type 'file'>
>>>
Moreover, you cannot use the len built-in on this object:
>>> len(open('test.txt', 'r+'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'file' has no len()
>>>
This is because, technically, a file object has no length. It is just a pointer to a certain file.
As you noted, the way to fix the problem is to first invoke the file object's read method. Doing so will return the file's contents as a string, which you can then use len on:
>>> open('test.txt', 'r+').read()
'hello world'
>>> len(open('test.txt', 'r+').read())
11
>>>
In the second example you are trying to find the length of the file pointer, which is not possible. SO add:
file_read.read()
instead of just file_read
When using len, it only accepts objects with a certain type if you're passing in an object with <type 'file'> it will throw an exception.
>>> f = open('/some/file/path', 'r+')
>>> type(f)
<type 'file'>
>>>
>>> type(f.read()) # the read method returns an object with type 'str'
<type 'str'>
Here f.read() returns a str object.
I've a simple question about file string manipulation.
I've written a bit of code that finally works other than for the final message. For the sake of my explanation, please have a look at a simplified version of my code below.
outStream = "/Users/andreamoro/Desktop/domains_output.csv"
try:
outStream = open(outStream, "w")
...
do something
except:
....
else:
print "A new output file %s has been created." %os.path.basename(outStream)
my desired output should be just the filename ... instead I get an exception like this
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 121, in basename
i = p.rfind('/') + 1
AttributeError: 'file' object has no attribute 'rfind'
I'm certainly using the wrong method, and I cannot expect to cast a file type into a string. I'm surprised there is not a method to return just the file name, and if it exist I wasn't able to find it.
Can you please point in the right direction?
Thanks
The problem in your code is that you re-assigned outStream to a file object.
outStream = "/Users/andreamoro/Desktop/domains_output.csv"
try:
outStream = open(outStream, "w") # now outStream is this
Rename either the string object or the file object and your code will work fine.
Otherwise it works fine:
>>> strs = "/Users/andreamoro/Desktop/domains_output.csv"
>>> os.path.basename(strs)
'domains_output.csv'
outStream variable is reassigned and becomes a file-like object:
outStream = open(outStream, "w")
Now you can get the name of the file from outStream.name:
name
If the file object was created using open(), the name of the
file. Otherwise, some string that indicates the source of the file
object, of the form "<...>". This is a read-only attribute and may not
be present on all file-like objects.
(docs)
os.path.basename(outStream.name) # is equal to 'domains_output.csv'
tempfile.mkstemp() returns:
a tuple containing an OS-level handle to an open file (as would be returned by os.open()) and the absolute pathname of that file, in that order.
How do I convert that OS-level handle to a file object?
The documentation for os.open() states:
To wrap a file descriptor in a "file
object", use fdopen().
So I tried:
>>> import tempfile
>>> tup = tempfile.mkstemp()
>>> import os
>>> f = os.fdopen(tup[0])
>>> f.write('foo\n')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IOError: [Errno 9] Bad file descriptor
You can use
os.write(tup[0], "foo\n")
to write to the handle.
If you want to open the handle for writing you need to add the "w" mode
f = os.fdopen(tup[0], "w")
f.write("foo")
Here's how to do it using a with statement:
from __future__ import with_statement
from contextlib import closing
fd, filepath = tempfile.mkstemp()
with closing(os.fdopen(fd, 'w')) as tf:
tf.write('foo\n')
You forgot to specify the open mode ('w') in fdopen(). The default is 'r', causing the write() call to fail.
I think mkstemp() creates the file for reading only. Calling fdopen with 'w' probably reopens it for writing (you can reopen the file created by mkstemp).
temp = tempfile.NamedTemporaryFile(delete=False)
temp.file.write('foo\n')
temp.close()
What's your goal, here? Is tempfile.TemporaryFile inappropriate for your purposes?
I can't comment on the answers, so I will post my comment here:
To create a temporary file for write access you can use tempfile.mkstemp and specify "w" as the last parameter, like:
f = tempfile.mkstemp("", "", "", "w") # first three params are 'suffix, 'prefix', 'dir'...
os.write(f[0], "write something")