Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #91342 > unrolled thread
| Started by | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| First post | 2015-05-28 12:16 +1000 |
| Last post | 2015-05-28 10:29 +0100 |
| Articles | 10 — 7 participants |
Back to article view | Back to comp.lang.python
Returning a custom file object (Python 3) Steven D'Aprano <steve@pearwood.info> - 2015-05-28 12:16 +1000
Re: Returning a custom file object (Python 3) Ben Finney <ben+python@benfinney.id.au> - 2015-05-28 12:40 +1000
Re: Returning a custom file object (Python 3) Marko Rauhamaa <marko@pacujo.net> - 2015-05-28 08:29 +0300
Re: Returning a custom file object (Python 3) Chris Angelico <rosuav@gmail.com> - 2015-05-28 15:49 +1000
Re: Returning a custom file object (Python 3) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-05-28 17:04 +1000
Re: Returning a custom file object (Python 3) Chris Angelico <rosuav@gmail.com> - 2015-05-28 19:06 +1000
Re: Returning a custom file object (Python 3) Gary Herron <gherron@digipen.edu> - 2015-05-27 22:56 -0700
Re: Returning a custom file object (Python 3) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-05-28 16:52 +1000
Re: Returning a custom file object (Python 3) Ben Finney <ben+python@benfinney.id.au> - 2015-05-28 12:34 +1000
Re: Returning a custom file object (Python 3) Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2015-05-28 10:29 +0100
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-05-28 12:16 +1000 |
| Subject | Returning a custom file object (Python 3) |
| Message-ID | <55667a6d$0$13002$c3e8da3$5496439d@news.astraweb.com> |
I'd like to return a custom file object, say my own subclass. I can easily
subclass the file object:
from io import TextIOWrapper
class MyFile(TextIOWrapper):
pass
but how do I tell open() to use MyFile?
Answers for Python 3, thanks.
--
Steven
[toc] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2015-05-28 12:40 +1000 |
| Message-ID | <mailman.113.1432780860.5151.python-list@python.org> |
| In reply to | #91342 |
Ben Finney <ben+python@benfinney.id.au> writes: > Steven D'Aprano <steve@pearwood.info> writes: > > > but how do I tell open() to use MyFile? > > I haven't used it, but does the ‘opener’ parameter do what you want? No, it doesn't; the ‘opener’ parameter doesn't have any say in the type of object returned from ‘open’. It seems the existing ‘open’ implementation doesn't allow you to override the type of object returned. You may have to resort to monkey-patching the ‘io’ attributes to put your preferred classes there. -- \ “Science shows that belief in God is not only obsolete. It is | `\ also incoherent.” —Victor J. Stenger, 2001 | _o__) | Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-05-28 08:29 +0300 |
| Message-ID | <87wpztclsu.fsf@elektro.pacujo.net> |
| In reply to | #91343 |
Ben Finney <ben+python@benfinney.id.au>: > It seems the existing ‘open’ implementation doesn't allow you to > override the type of object returned. The question is, can you assign to the builtin namespace. I'm guessing you can't. Within a module, you can simply do: open = MyFile Also, in other modules, you can: from myfile import open Marko
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-05-28 15:49 +1000 |
| Message-ID | <mailman.119.1432792558.5151.python-list@python.org> |
| In reply to | #91350 |
On Thu, May 28, 2015 at 3:29 PM, Marko Rauhamaa <marko@pacujo.net> wrote:
> Ben Finney <ben+python@benfinney.id.au>:
>
>> It seems the existing ‘open’ implementation doesn't allow you to
>> override the type of object returned.
>
> The question is, can you assign to the builtin namespace. I'm guessing
> you can't.
>
> Within a module, you can simply do:
>
> open = MyFile
>
> Also, in other modules, you can:
>
> from myfile import open
Well, you can...
>>> import builtins
>>> builtins.open
<built-in function open>
>>> builtins.open = "not your grandfather's open() function"
>>> open
"not your grandfather's open() function"
... but I don't think replacing all of open() is what Steven has in
mind; it's a function that does a lot of work, most of which is what's
wanted.
Depending on how brutal you want to be, though, you _could_ hack around it.
>>> from io import TextIOWrapper
>>> class MyFile(TextIOWrapper):
... def demo(self): print("Hello, world!")
...
>>> f = open("/tmp/dummy", "w", encoding="utf-8")
>>> f
<_io.TextIOWrapper name='/tmp/dummy' mode='w' encoding='utf-8'>
>>> f.__class__
<class '_io.TextIOWrapper'>
>>> f.__class__ = MyFile
>>> f.demo()
Hello, world!
This does appear to work. Whether or not it's a good idea is a
separate question. And of course, you could replace open() with
something like this:
>>> _orig_open = open
>>> def open(*args, **kw):
... cls = kw.pop("use_class", None)
... f = _orig_open(*args, **kw)
... if cls is not None: f.__class__ = cls
... return f
...
>>> f = open("/tmp/dummy", "w", encoding="utf-8", use_class=MyFile)
>>> f
<_io.TextIOWrapper name='/tmp/dummy' mode='w' encoding='utf-8'>
>>> f.demo()
Hello, world!
But again, I'm really not sure this is a good way to do things.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2015-05-28 17:04 +1000 |
| Message-ID | <5566bdf4$0$13013$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #91351 |
On Thursday 28 May 2015 15:49, Chris Angelico wrote:
> ... but I don't think replacing all of open() is what Steven has in
> mind; it's a function that does a lot of work, most of which is what's
> wanted.
Correct. If I wanted to replace open(), I would have just shadowed it, or
monkey-patched it, or just used myopen().
I want open() to return my own subclass instead of the standard one. And I
think you have the solution I was looking for:
> Depending on how brutal you want to be, though, you _could_ hack around
> it.
>
>>>> from io import TextIOWrapper
>>>> class MyFile(TextIOWrapper):
> ... def demo(self): print("Hello, world!")
> ...
>>>> f = open("/tmp/dummy", "w", encoding="utf-8")
>>>> f
> <_io.TextIOWrapper name='/tmp/dummy' mode='w' encoding='utf-8'>
>>>> f.__class__
> <class '_io.TextIOWrapper'>
>>>> f.__class__ = MyFile
>>>> f.demo()
> Hello, world!
>
> This does appear to work. Whether or not it's a good idea is a
> separate question.
And this is EXACTLY the sort of use-case that having __class__ be writable
is intended to solve. So this is exactly the solution I was after, thank
you. Er... except for one little problem... in Python 3.3:
py> f = open("/tmp/a", "r")
py> f.__class__ = MyFile
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
So it doesn't work for me. What version of Python are you using?
--
Steve
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-05-28 19:06 +1000 |
| Message-ID | <mailman.121.1432804427.5151.python-list@python.org> |
| In reply to | #91354 |
On Thu, May 28, 2015 at 5:04 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
>> This does appear to work. Whether or not it's a good idea is a
>> separate question.
>
>
> And this is EXACTLY the sort of use-case that having __class__ be writable
> is intended to solve. So this is exactly the solution I was after, thank
> you. Er... except for one little problem... in Python 3.3:
>
> py> f = open("/tmp/a", "r")
> py> f.__class__ = MyFile
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: __class__ assignment: only for heap types
>
>
> So it doesn't work for me. What version of Python are you using?
Huh, didn't even think to check other versions.
$ python3
Python 3.5.0b1+ (default:7255af1a1c50+, May 26 2015, 00:39:06)
[GCC 4.9.2] on linux
It's a build fresh from source control around about this weekend (some
time after feature freeze, obviously, but beyond that all I know is
what you see there). I guess this is pretty new; trying the same thing
on 3.4.2 doesn't work. But hey! 3.5 will be out soon...
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Gary Herron <gherron@digipen.edu> |
|---|---|
| Date | 2015-05-27 22:56 -0700 |
| Message-ID | <mailman.120.1432792612.5151.python-list@python.org> |
| In reply to | #91350 |
On 05/27/2015 10:29 PM, Marko Rauhamaa wrote: > Ben Finney <ben+python@benfinney.id.au>: > >> It seems the existing ‘open’ implementation doesn't allow you to >> override the type of object returned. > The question is, can you assign to the builtin namespace. I'm guessing > you can't. Of course you can. Python2: >>> __builtins__.open = "whatever" >>> Python3: >>> import builtins >>> builtins.open = "whatever" >>> Of course doing so is like shooting yourself in the foot: Any subsequent pain is your own fault and probably well deserved. Gary Herron > > Within a module, you can simply do: > > open = MyFile > > Also, in other modules, you can: > > from myfile import open > > > Marko -- Dr. Gary Herron Department of Computer Science DigiPen Institute of Technology (425) 895-4418
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2015-05-28 16:52 +1000 |
| Message-ID | <5566bb2a$0$11126$c3e8da3@news.astraweb.com> |
| In reply to | #91352 |
On Thursday 28 May 2015 15:56, Gary Herron wrote: > On 05/27/2015 10:29 PM, Marko Rauhamaa wrote: >> Ben Finney <ben+python@benfinney.id.au>: >> >>> It seems the existing ‘open’ implementation doesn't allow you to >>> override the type of object returned. >> The question is, can you assign to the builtin namespace. I'm guessing >> you can't. > > Of course you can. > > Python2: > >>> __builtins__.open = "whatever" Don't use __builtins__ with an "s". That's an implementation of CPython and may not exist in the future, and doesn't exist in other implementations. Instead, you should import __builtin__ with no "s". Confusing? It certainly is, which is why Python 3 renamed __builtin__ to builtins. -- Steve
[toc] | [prev] | [next] | [standalone]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2015-05-28 12:34 +1000 |
| Message-ID | <mailman.112.1432780501.5151.python-list@python.org> |
| In reply to | #91342 |
Steven D'Aprano <steve@pearwood.info> writes:
> from io import TextIOWrapper
> class MyFile(TextIOWrapper):
> pass
>
> but how do I tell open() to use MyFile?
I haven't used it, but does the ‘opener’ parameter do what you want?
open(file, mode='r', buffering=-1, encoding=None,
errors=None, newline=None, closefd=True, opener=None) ->
file object
[…]
A custom opener can be used by passing a callable as *opener*. The
underlying file descriptor for the file object is then obtained by
calling *opener* with (*file*, *flags*). *opener* must return an
open file descriptor (passing os.open as *opener* results in
functionality similar to passing None).
--
\ “Our products just aren't engineered for security.” —Brian |
`\ Valentine, senior vice-president of Microsoft Windows |
_o__) development |
Ben Finney
[toc] | [prev] | [next] | [standalone]
| From | Oscar Benjamin <oscar.j.benjamin@gmail.com> |
|---|---|
| Date | 2015-05-28 10:29 +0100 |
| Message-ID | <mailman.122.1432805768.5151.python-list@python.org> |
| In reply to | #91342 |
On 28 May 2015 at 03:16, Steven D'Aprano <steve@pearwood.info> wrote:
> I'd like to return a custom file object, say my own subclass. I can easily
> subclass the file object:
>
>
> from io import TextIOWrapper
> class MyFile(TextIOWrapper):
> pass
>
>
> but how do I tell open() to use MyFile?
Does the below do what you want?
#!/usr/bin/env python3
class Wrapper:
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, attrname):
return getattr(self._wrapped, attrname)
# Special methods are not resolved by __getattr__
def __iter__(self):
return self._wrapped.__iter__()
def __enter__(self):
return self._wrapped.__enter__()
def __exit__(self, *args):
return self._wrapped.__exit__(*args)
class WrapFile(Wrapper):
def write(self):
return "Writing..."
f = WrapFile(open('wrap.py'))
print(f.readline())
with f:
print(len(list(f)))
print(f.write())
>
> Answers for Python 3, thanks.
Tested on 3.2.
--
Oscar
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web