Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #32942 > unrolled thread

isinstance(.., file) for Python 3

Started byUlrich Eckhardt <ulrich.eckhardt@dominolaser.com>
First post2012-11-08 13:05 +0100
Last post2012-11-08 16:14 +0100
Articles 7 — 7 participants

Back to article view | Back to comp.lang.python


Contents

  isinstance(.., file) for Python 3 Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> - 2012-11-08 13:05 +0100
    Re: isinstance(.., file) for Python 3 MRAB <python@mrabarnett.plus.com> - 2012-11-08 12:54 +0000
    Re: isinstance(.., file) for Python 3 Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2012-11-08 12:56 +0000
    Re: isinstance(.., file) for Python 3 Chris Angelico <rosuav@gmail.com> - 2012-11-08 23:57 +1100
    Re: isinstance(.., file) for Python 3 Peter Otten <__peter__@web.de> - 2012-11-08 14:02 +0100
    Re: isinstance(.., file) for Python 3 Duncan Booth <duncan.booth@invalid.invalid> - 2012-11-08 13:58 +0000
      Re: isinstance(.., file) for Python 3 Stefan Behnel <stefan_ml@behnel.de> - 2012-11-08 16:14 +0100

#32942 — isinstance(.., file) for Python 3

FromUlrich Eckhardt <ulrich.eckhardt@dominolaser.com>
Date2012-11-08 13:05 +0100
Subjectisinstance(.., file) for Python 3
Message-ID<2pjsm9-p8h.ln1@satorlaser.homedns.org>
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

[toc] | [next] | [standalone]


#32943

FromMRAB <python@mrabarnett.plus.com>
Date2012-11-08 12:54 +0000
Message-ID<mailman.3430.1352379260.27098.python-list@python.org>
In reply to#32942
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!

[toc] | [prev] | [next] | [standalone]


#32945

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2012-11-08 12:56 +0000
Message-ID<509bac19$0$29980$c3e8da3$5496439d@news.astraweb.com>
In reply to#32942
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

[toc] | [prev] | [next] | [standalone]


#32946

FromChris Angelico <rosuav@gmail.com>
Date2012-11-08 23:57 +1100
Message-ID<mailman.3432.1352379430.27098.python-list@python.org>
In reply to#32942
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

[toc] | [prev] | [next] | [standalone]


#32947

FromPeter Otten <__peter__@web.de>
Date2012-11-08 14:02 +0100
Message-ID<mailman.3433.1352379748.27098.python-list@python.org>
In reply to#32942
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


[toc] | [prev] | [next] | [standalone]


#32949

FromDuncan Booth <duncan.booth@invalid.invalid>
Date2012-11-08 13:58 +0000
Message-ID<XnsA1058E1707A9duncanbooth@127.0.0.1>
In reply to#32942
Ulrich Eckhardt <ulrich.eckhardt@dominolaser.com> 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 ...

-- 
Duncan Booth http://kupuguy.blogspot.com

[toc] | [prev] | [next] | [standalone]


#32956

FromStefan Behnel <stefan_ml@behnel.de>
Date2012-11-08 16:14 +0100
Message-ID<mailman.3443.1352387690.27098.python-list@python.org>
In reply to#32949
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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web