I am trying to write a method that will accept either an opened file
myFile = open("myFile.txt")
obj.writeTo(myFile)
myFile.close()
or a string with a path
obj.writeTo("myFile.txt")
The method is implemented as follows:
def writeTo(self, hessianFile):
if isinstance(hessianFile,file):
print("File type")
elif isinstance(hessianFile,str):
print("String type")
else:
pass
But this raises an error
NameError: global name 'file' is not defined
why is file type not defined? Shouldn’t file be defined all the time? How should the implementation be corrected to properly handel both path an file as valid argument types
Don’t type check! It’s not Pythonic. The core of duck typing is the idea that if it quacks like a duck, it is a duck. The behaviour you want is if it is file-like, it works, and if it is string-like, it works. This isn’t just ideological – because this is the standard in Python, people will expect to be able to give you a file-like object and have it work. If you restrict it to only a specific file type, your code will be fragile and inflexible.
The simplest option is to simply pick the more common outcome, try to work as you would with that, and fail to the other method if you get an exception:
This might seem bad if you are used to other languages where “using exceptions for flow control” is considered bad, but that isn’t the case in Python, where they are a core part of the language regularly used that way (every for loop ends with an exception!).
Or, if you think you are more likely to get a file object most of the time, do it the other way around:
Note my use of the
withstatement which is the best way of dealing with opening files – it’s more readable, and also always closes the file for you, even on exceptions.If you really find you have to type check (e.g: the operation is extremely expensive even if it fails, with no way to short-circuit), you should check the string side, as it is easier to work out if something is string-like as opposed to file-like. If you have to check for something file-like, you should implement an abstract base class and look for the functionality you need, rather than actually type-checking.
The reason your original code failed is that
fileisn’t the base class of objects returned byopen()in 3.x.So for that you want
io.FileIO.