isinstance(.., file) for Python 3

Discussion in 'Python' started by Ulrich Eckhardt, Nov 8, 2012.

  1. 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
    Ulrich Eckhardt, Nov 8, 2012
    #1
    1. Advertising

  2. Ulrich Eckhardt

    MRAB Guest

    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!
    MRAB, Nov 8, 2012
    #2
    1. Advertising

  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
    Steven D'Aprano, Nov 8, 2012
    #3
  4. On Thu, Nov 8, 2012 at 11:05 PM, 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...


    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
    Chris Angelico, Nov 8, 2012
    #4
  5. Ulrich Eckhardt

    Peter Otten Guest

    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
    Peter Otten, Nov 8, 2012
    #5
  6. 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
    Stefan Behnel, Nov 8, 2012
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Joona I Palaste

    Re: isInstance problem

    Joona I Palaste, Jul 1, 2003, in forum: Java
    Replies:
    4
    Views:
    1,016
    George W. Cherry
    Jul 2, 2003
  2. Ben Jessel

    Re: isInstance problem

    Ben Jessel, Jul 10, 2003, in forum: Java
    Replies:
    0
    Views:
    387
    Ben Jessel
    Jul 10, 2003
  3. Lambert, David W (S&T)

    Python 3 isinstance

    Lambert, David W (S&T), Jan 14, 2009, in forum: Python
    Replies:
    2
    Views:
    393
    Rhamphoryncus
    Jan 16, 2009
  4. Lambert, David W (S&T)

    Re: Python 3 isinstance

    Lambert, David W (S&T), Jan 15, 2009, in forum: Python
    Replies:
    2
    Views:
    253
    Steven D'Aprano
    Jan 15, 2009
  5. Terry Reedy

    Re: Python 3 isinstance

    Terry Reedy, Jan 15, 2009, in forum: Python
    Replies:
    4
    Views:
    1,511
    Steven D'Aprano
    Jan 16, 2009
Loading...

Share This Page