Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   isinstance(.., file) for Python 3 (http://www.velocityreviews.com/forums/t954332-isinstance-file-for-python-3-a.html)

Ulrich Eckhardt 11-08-2012 12:05 PM

isinstance(.., file) for Python 3
 
Hi!

I have two problems that are related and that I'd like to solve together.

Firstly, I have code that allows either a file or a string representing
its content as parameter. If the parameter is a file, the content is
read from the file. In Python 2, I used "isinstance(p, file)" to
determine whether the parameter p is a file. In Python 3, the
returnvalue of open() is of type _io.TextIOWrapper, while the built-in
class file doesn't exist, so I can't use that code.

Secondly, checking for the type is kind-of ugly, because it means that I
can't use an object that fits but that doesn't have the right type. In
other words, it breaks duck-typing. This is already broken in the Python
2 code, but since I have to touch the code anyway, I might as well fix
it on the way.

If possible, I'm looking for a solution that works for Pythons 2 and 3,
since I'm not fully through the conversion yet and have clients that
might use the older snake for some time before shedding their skin.

Suggestions?

Uli



MRAB 11-08-2012 12:54 PM

Re: isinstance(.., file) for Python 3
 
On 2012-11-08 12:05, Ulrich Eckhardt wrote:
> Hi!
>
> I have two problems that are related and that I'd like to solve together.
>
> Firstly, I have code that allows either a file or a string representing
> its content as parameter. If the parameter is a file, the content is
> read from the file. In Python 2, I used "isinstance(p, file)" to
> determine whether the parameter p is a file. In Python 3, the
> returnvalue of open() is of type _io.TextIOWrapper, while the built-in
> class file doesn't exist, so I can't use that code.
>
> Secondly, checking for the type is kind-of ugly, because it means that I
> can't use an object that fits but that doesn't have the right type. In
> other words, it breaks duck-typing. This is already broken in the Python
> 2 code, but since I have to touch the code anyway, I might as well fix
> it on the way.
>
> If possible, I'm looking for a solution that works for Pythons 2 and 3,
> since I'm not fully through the conversion yet and have clients that
> might use the older snake for some time before shedding their skin.
>
> Suggestions?
>

Instead of checking whether it's a file, check whether it's a string!

Steven D'Aprano 11-08-2012 12:56 PM

Re: isinstance(.., file) for Python 3
 
On Thu, 08 Nov 2012 13:05:22 +0100, Ulrich Eckhardt wrote:

> Firstly, I have code that allows either a file or a string representing
> its content as parameter. If the parameter is a file, the content is
> read from the file. In Python 2, I used "isinstance(p, file)" to
> determine whether the parameter p is a file. In Python 3, the
> returnvalue of open() is of type _io.TextIOWrapper,


Incorrect.

py> type(open('x', 'wb'))
<class '_io.BufferedWriter'>

The type returned by open will depend on what you open and how you open
it.

> while the built-in
> class file doesn't exist, so I can't use that code.


import io
file = io._IOBase

will probably work. But consider it a little smelly, since you're relying
on an implementation detail.


> Secondly, checking for the type is kind-of ugly, because it means that I
> can't use an object that fits but that doesn't have the right type. In
> other words, it breaks duck-typing. This is already broken in the Python
> 2 code, but since I have to touch the code anyway, I might as well fix
> it on the way.


if hasattr(obj, 'read'):
# object is file-like enough to treat as a file
pass

That means that you can also use io.StringIO objects as pseudo-files too.



--
Steven

Chris Angelico 11-08-2012 12:57 PM

Re: isinstance(.., file) for Python 3
 
On Thu, Nov 8, 2012 at 11:05 PM, Ulrich Eckhardt
<ulrich.eckhardt@dominolaser.com> wrote:
> Firstly, I have code that allows either a file or a string representing its
> content as parameter. If the parameter is a file, the content is read from
> the file. In Python 2, I used "isinstance(p, file)" to determine whether the
> parameter p is a file...


Can you use the inverted check "isinstance(p, str)"? It's more likely
that you'll want to pass a file-like object than a string-like object.
This would work on Python 2 as well, though it's semantically
different; to safely check for both Unicode and bytes strings on both
Py2 and Py3, this may work:

# Once-off:
try:
basestring
except NameError:
basestring = (str, bytes)

# Is p a string?
if isinstance(p, basestring):
pass

It abuses the fact that isinstance will happily accept the
'basestring' common supertype of both strings in Python 2, but will
equally happily accept a tuple of types.

ChrisA

Peter Otten 11-08-2012 01:02 PM

Re: isinstance(.., file) for Python 3
 
Ulrich Eckhardt wrote:

> Hi!
>
> I have two problems that are related and that I'd like to solve together.
>
> Firstly, I have code that allows either a file or a string representing
> its content as parameter. If the parameter is a file, the content is
> read from the file. In Python 2, I used "isinstance(p, file)" to
> determine whether the parameter p is a file. In Python 3, the
> returnvalue of open() is of type _io.TextIOWrapper, while the built-in
> class file doesn't exist, so I can't use that code.
>
> Secondly, checking for the type is kind-of ugly, because it means that I
> can't use an object that fits but that doesn't have the right type. In
> other words, it breaks duck-typing. This is already broken in the Python
> 2 code, but since I have to touch the code anyway, I might as well fix
> it on the way.
>
> If possible, I'm looking for a solution that works for Pythons 2 and 3,
> since I'm not fully through the conversion yet and have clients that
> might use the older snake for some time before shedding their skin.
>
> Suggestions?


In order of obviousness:
hasattr(p, "read")
not isinstance(p, str)
iter(p) is p

Or you change the interface

def f(*, contents=None, file=None):
if contents is None:
with open(file) as f:
contents = f.read()
... # work with contents




Stefan Behnel 11-08-2012 03:14 PM

Re: isinstance(.., file) for Python 3
 
Duncan Booth, 08.11.2012 14:58:
> Ulrich Eckhardt wrote:
>> If possible, I'm looking for a solution that works for Pythons 2 and 3,
>> since I'm not fully through the conversion yet and have clients that
>> might use the older snake for some time before shedding their skin.
>>
>> Suggestions?

>
> Why bother checking types at all?
>
> def foo(file_or_string):
> try:
> data = file_or_string.read()
> except AttributeError:
> data = file_or_string
> ... use data ...


Or, a tiny bit more safely:

try:
read = file_or_string.read
except AttributeError:
data = file_or_string
else:
data = read()

I'd rather go with one of the previous solutions, though.

Stefan




All times are GMT. The time now is 05:56 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.