Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #44944 > unrolled thread
| Started by | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| First post | 2013-05-08 08:52 +0000 |
| Last post | 2013-05-13 08:15 -0500 |
| Articles | 20 on this page of 82 — 23 participants |
Back to article view | Back to comp.lang.python
object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-08 08:52 +0000
Re: object.enable() anti-pattern Christian Heimes <christian@python.org> - 2013-05-08 11:51 +0200
Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-08 11:13 +0100
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-08 12:30 +0000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-08 09:17 -0400
Re: object.enable() anti-pattern Duncan Booth <duncan.booth@invalid.invalid> - 2013-05-08 14:27 +0000
Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-09 02:38 +0000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 05:37 +0000
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-09 15:52 +1000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 03:12 +0000
Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-09 02:42 +0000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 05:23 +0000
Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-09 02:41 -0400
Re: object.enable() anti-pattern Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-09 19:54 +1200
Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-09 18:23 +1000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 11:30 +0000
Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-10 09:36 +1000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 05:00 +0000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 01:50 -0400
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 09:47 +0000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 09:22 -0400
Re: object.enable() anti-pattern Cameron Simpson <cs@zip.com.au> - 2013-05-11 08:25 +1000
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 20:16 -0700
Re: object.enable() anti-pattern Thomas Rachel <nutznetz-0c1b6768-bfa9-48d5-a470-7603bd3aa915@spamschutz.glglgl.de> - 2013-05-11 06:21 +0200
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 21:00 -0700
Re: object.enable() anti-pattern Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-11 15:04 -0400
Re: object.enable() anti-pattern Greg Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-10 10:56 +1200
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 09:07 -0400
Re: object.enable() anti-pattern Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-09 14:51 +0100
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 18:21 +0000
Re: object.enable() anti-pattern MRAB <python@mrabarnett.plus.com> - 2013-05-09 19:34 +0100
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 02:30 +0000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 23:09 -0400
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-09 20:19 -0700
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 13:46 +1000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 05:03 +0000
Re: object.enable() anti-pattern Dan Sommers <dan@tombstonezero.net> - 2013-05-10 06:22 +0000
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-10 11:00 +0000
Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 13:19 +0100
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:01 -0400
Re: object.enable() anti-pattern Oscar Benjamin <oscar.j.benjamin@gmail.com> - 2013-05-10 15:29 +0100
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:37 -0400
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 00:46 +1000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 10:54 -0400
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 01:09 +1000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 11:21 -0400
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 01:44 +1000
Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 16:33 +0100
Re: object.enable() anti-pattern Serhiy Storchaka <storchaka@gmail.com> - 2013-05-10 18:44 +0300
Re: object.enable() anti-pattern André Malo <ndparker@gmail.com> - 2013-05-11 17:33 +0200
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-12 02:04 +1000
Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-10 18:20 +0100
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-11 07:51 +0000
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-11 09:31 -0400
Re: object.enable() anti-pattern Robert Kern <robert.kern@gmail.com> - 2013-05-11 20:55 +0100
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-12 08:39 +1000
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-11 03:24 +1000
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-10 19:43 -0700
Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-12 11:48 -0500
Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-12 16:23 -0400
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-09 20:51 -0700
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 13:08 +1000
Re: object.enable() anti-pattern roy@panix.com (Roy Smith) - 2013-05-09 14:59 -0400
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-10 07:55 +1000
Re: object.enable() anti-pattern Nobody <nobody@nowhere.com> - 2013-05-10 17:59 +0100
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-10 13:32 -0400
Re: object.enable() anti-pattern Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2013-05-11 15:24 -0400
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-11 07:05 +0000
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-08 19:53 -0700
Re: object.enable() anti-pattern Mark Janssen <dreamingforward@gmail.com> - 2013-05-08 19:56 -0700
Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-09 06:08 -0500
Re: object.enable() anti-pattern Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-05-09 11:51 +0000
Re: object.enable() anti-pattern Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-10 11:43 +1200
Re: object.enable() anti-pattern Michael Speer <knomenet@gmail.com> - 2013-05-09 20:18 -0400
Re: object.enable() anti-pattern Roy Smith <roy@panix.com> - 2013-05-09 20:50 -0400
Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-12 12:14 -0500
Re: object.enable() anti-pattern Terry Jan Reedy <tjreedy@udel.edu> - 2013-05-12 16:03 -0400
Re: object.enable() anti-pattern Greg Ewing <greg.ewing@canterbury.ac.nz> - 2013-05-13 11:18 +1200
Re: object.enable() anti-pattern Fábio Santos <fabiosantosart@gmail.com> - 2013-05-13 07:32 +0100
Re: object.enable() anti-pattern Chris Angelico <rosuav@gmail.com> - 2013-05-13 17:36 +1000
Re: object.enable() anti-pattern Fábio Santos <fabiosantosart@gmail.com> - 2013-05-13 09:09 +0100
Re: object.enable() anti-pattern Wayne Werner <wayne@waynewerner.com> - 2013-05-13 08:15 -0500
Page 4 of 5 — ← Prev page 1 2 3 [4] 5 Next page →
| From | Mark Janssen <dreamingforward@gmail.com> |
|---|---|
| Date | 2013-05-09 20:51 -0700 |
| Message-ID | <mailman.1553.1368273954.3114.python-list@python.org> |
| In reply to | #45075 |
>> In the old days, it was useful to have fine-grained control over the >> file object because you didn't know where it might fail, and the OS >> didn't necessarily give you give good status codes. So being able to >> step through the entire process was the job of the progammers. > > I don't know what you mean by the "old days", but a couple of decades > ago, there were no such things as "file objects". My apologies. I used the word "object" when I shouldn't have. > I'm beginning to wonder if you and Dihedral are swapping notes. > Dihedral's been sounding fairly coherent lately. Dihedral... That's my dream-self. Where did you encounter him? heh -- MarkJ Tacoma, Washington
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-05-10 13:08 +1000 |
| Message-ID | <mailman.1518.1368155286.3114.python-list@python.org> |
| In reply to | #45073 |
On Fri, May 10, 2013 at 12:30 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> I must admit I am astonished at how controversial the opinion "if your
> object is useless until you call 'start', you should automatically call
> 'start' when the object is created" has turned out to be.
I share your astonishment. This is a very simple point: If, after
constructing an object, the caller MUST call some method on it prior
to the object being of use, then better design is to embed that call
directly into the constructor. As always, it has its exceptions, but
that doesn't stop it being a useful rule.
The Path() equivalent would be:
p = Path()
p.set_path("/foo/bar")
if p.exists():
pass
Even if you have a set_path() method, it makes good sense to symlink
it to __init__ to avoid this anti-pattern.
C level APIs often have these sorts of initialization requirements.
fd_set selectme;
FD_ZERO(&selectme);
This is because declaring a variable in C cannot initialize it.
Anything that *has* constructors should be using them to set objects
up... that's what they're for.
Where's the controversy?
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | roy@panix.com (Roy Smith) |
|---|---|
| Date | 2013-05-09 14:59 -0400 |
| Message-ID | <kmgrme$56s$1@panix2.panix.com> |
| In reply to | #45051 |
In article <518be931$0$29997$c3e8da3$5496439d@news.astraweb.com>,
Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> There is no sensible use-case for creating a file OBJECT unless it
> initially wraps an open file pointer.
OK, I guess that's a fair statement. But mostly because a python file
object only exposes those subset of operations you can do on file
descriptors which deal with reading and writing the contents of a
file.
It would not be true if python file objects included methods for
querying and manipulating file metadata. It's not hard to imagine a
file class which could be used like:
f = file("/path/to/my/file")
f.delete()
That would be a totally different model from the current python file
object. And then there would be plenty of things you might want to do
to a file other than open it...
file("/path/to/my/directory").chdir()
file("/dev/sdf").mount("/var/lib/whatever")
file("/mnt/swapfile").swapon()
> The standard C I/O library doesn't support creating a file
> descriptor unless it is a file descriptor to an open file [...]
> there is no corresponding function to create a *closed* file
> description. (Because such a thing would be pointless.)
What about sockets? From the python standard library:
s = socket.socket()
Now what? You can't do much with your shiny new socket until you call
bind() or connect(), or a few other things. At least not for TCP.
This is essentially the two-phased construction pattern. Of course,
the python socket module just exposes the semantics of the underlying
OS sockets, so there's not a lot of choice there.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-05-10 07:55 +1000 |
| Message-ID | <mailman.1506.1368136558.3114.python-list@python.org> |
| In reply to | #45054 |
On Fri, May 10, 2013 at 4:59 AM, Roy Smith <roy@panix.com> wrote:
> It's not hard to imagine a
> file class which could be used like:
>
> f = file("/path/to/my/file")
> f.delete()
>
> That would be a totally different model from the current python file
> object. And then there would be plenty of things you might want to do
> to a file other than open it...
>
> file("/path/to/my/directory").chdir()
> file("/dev/sdf").mount("/var/lib/whatever")
> file("/mnt/swapfile").swapon()
Sure, you can imagine it. But what does it do that can't be done with
a moduleful of flat functions accepting strings? This makes sense in
Java, I guess, but why do it in Python?
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Nobody <nobody@nowhere.com> |
|---|---|
| Date | 2013-05-10 17:59 +0100 |
| Message-ID | <pan.2013.05.10.16.59.31.512000@nowhere.com> |
| In reply to | #45002 |
On Thu, 09 May 2013 05:23:59 +0000, Steven D'Aprano wrote: > There is no sensible use-case for creating a file without opening it. > What would be the point? Any subsequent calls to just about any method > will fail. Since you have to open the file after creating the file object > anyway, why make them two different calls? As a counterpoint, some OSes (e.g. Plan 9) allow you to get a "handle" to a file without opening it. This can then be used for deleting, renaming or stat()-type operations without either the risk of race conditions (if another process renames files between operations, the operations may be performed on different files) or the side-effects of actually opening the file (particularly for device files, e.g. opening a tape drive may rewind the tape). Python's file model doesn't allow for this, so there isn't really anything meaningful that you can do on a file object which isn't open (although these actually exist; any file object on which the .close() method has been called will be in this state). However: there are situations where it is useful to be able to separate the simple task of creating an object from more invasive actions such as system calls. Particularly in multi-threaded or real-time code (although the latter is a non-starter in Python for many other reasons).
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-05-10 13:32 -0400 |
| Message-ID | <roy-A06962.13325010052013@news.panix.com> |
| In reply to | #45115 |
In article <pan.2013.05.10.16.59.31.512000@nowhere.com>, Nobody <nobody@nowhere.com> wrote: > However: there are situations where it is useful to be able to separate > the simple task of creating an object from more invasive actions such as > system calls. Particularly in multi-threaded or real-time code (although > the latter is a non-starter in Python for many other reasons). Sure. I can serialize a path name. I can't serialize an open file descriptor.
[toc] | [prev] | [next] | [standalone]
| From | Dennis Lee Bieber <wlfraed@ix.netcom.com> |
|---|---|
| Date | 2013-05-11 15:24 -0400 |
| Message-ID | <mailman.1561.1368300272.3114.python-list@python.org> |
| In reply to | #45119 |
On Fri, 10 May 2013 13:32:50 -0400, Roy Smith <roy@panix.com> declaimed
the following in gmane.comp.python.general:
> In article <pan.2013.05.10.16.59.31.512000@nowhere.com>,
> Nobody <nobody@nowhere.com> wrote:
>
> > However: there are situations where it is useful to be able to separate
> > the simple task of creating an object from more invasive actions such as
> > system calls. Particularly in multi-threaded or real-time code (although
> > the latter is a non-starter in Python for many other reasons).
>
> Sure. I can serialize a path name. I can't serialize an open file
> descriptor.
I really need to pull a few books out of storage... My Amiga RKMs,
and my LS-DOS 6 "The Source" and programming manuals. As I recall, the
LS-DOS system calls for I/O crossed your line about serialization...
The file control block of an open file contained the information
about record length (from the directory), mode, and current position. If
one closed the file, the FCB contained the filename <G>
Granted, that system used a single layer directory (but did have a
utility that allowed for "partitioned data sets" -- a way of storing
multiple files within one larger file; most of the system libraries were
implemented that way).
--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-11 07:05 +0000 |
| Message-ID | <518ded9c$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #45115 |
On Fri, 10 May 2013 17:59:26 +0100, Nobody wrote: > On Thu, 09 May 2013 05:23:59 +0000, Steven D'Aprano wrote: > >> There is no sensible use-case for creating a file without opening it. >> What would be the point? Any subsequent calls to just about any method >> will fail. Since you have to open the file after creating the file >> object anyway, why make them two different calls? > > As a counterpoint, some OSes (e.g. Plan 9) allow you to get a "handle" > to a file without opening it. This can then be used for deleting, > renaming or stat()-type operations without either the risk of race > conditions (if another process renames files between operations, the > operations may be performed on different files) or the side-effects of > actually opening the file (particularly for device files, e.g. opening a > tape drive may rewind the tape). Ah, now that's a fantastic counter-example. But I think that says more about the primitiveness of the Unix file model than of the idea of temporal coupling. > Python's file model doesn't allow for this, so there isn't really > anything meaningful that you can do on a file object which isn't open > (although these actually exist; any file object on which the .close() > method has been called will be in this state). Absolutely correct, and I'm amazed it's taken this long for anyone to point this out :-) -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Mark Janssen <dreamingforward@gmail.com> |
|---|---|
| Date | 2013-05-08 19:53 -0700 |
| Message-ID | <mailman.1476.1368068018.3114.python-list@python.org> |
| In reply to | #44944 |
> I'm looking for some help in finding a term, it's not Python-specific but > does apply to some Python code. > > This is an anti-pattern to avoid. The idea is that creating a resource > ought to be the same as "turning it on", or enabling it, or similar. For > example, we don't do this in Python: I would call it "user-mediated resource allocation" as distinct from "object-mediated" resource allocation. -- MarkJ Tacoma, Washington
[toc] | [prev] | [next] | [standalone]
| From | Mark Janssen <dreamingforward@gmail.com> |
|---|---|
| Date | 2013-05-08 19:56 -0700 |
| Message-ID | <mailman.1477.1368068164.3114.python-list@python.org> |
| In reply to | #44944 |
>> This is an anti-pattern to avoid. The idea is that creating a resource >> ought to be the same as "turning it on", or enabling it, or similar. For >> example, we don't do this in Python: > > I would call it "user-mediated resource allocation" as distinct from > "object-mediated" resource allocation. I should point out, though, it's not really an anti-pattern (coming form the C community). -- MarkJ Tacoma, Washington
[toc] | [prev] | [next] | [standalone]
| From | Wayne Werner <wayne@waynewerner.com> |
|---|---|
| Date | 2013-05-09 06:08 -0500 |
| Message-ID | <mailman.1490.1368098298.3114.python-list@python.org> |
| In reply to | #44944 |
On Wed, 8 May 2013, Steven D'Aprano wrote:
> I'm looking for some help in finding a term, it's not Python-specific but
> does apply to some Python code.
>
> This is an anti-pattern to avoid. The idea is that creating a resource
> ought to be the same as "turning it on", or enabling it, or similar. For
> example, we don't do this in Python:
I'm not entirely sure what the name of it is, but the basic concept is
that you should never partially create, or create a class that can be in
an unstable state. Which isn't to say you should prevent invalid input,
only that with every valid input or single operation (including
construction) your class should be valid.
Ah, that's it - the problem is that it introduces /Temporal Coupling/ to
one's code: http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/
You don't ever want a class that has functions that need to be called in a
certain order to *not* crash. That's fine if you have to call them in a
certain sequence in order to get the correct data - that's what
programming is all about, after all. But if you provide me a class with a
constructor you better make sure that when I do this:
thing = YourSuperAwesomeClass()
thing.do_stuff()
that I don't get some horrid stack trace ending with
InvalidStateError: initialize() needs to be called before do_stuff()
Or something worse.
HTH,
Wayne
p.s. I'm interested in reading whatever is evenually written on the topic
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-09 11:51 +0000 |
| Message-ID | <518b8db9$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #45024 |
On Thu, 09 May 2013 06:08:25 -0500, Wayne Werner wrote: > Ah, that's it - the problem is that it introduces /Temporal Coupling/ to > one's code: http://blog.ploeh.dk/2011/05/24/DesignSmellTemporalCoupling/ Good catch! That's not the blog post I read, but that's the same concept. "Temporal Coupling" -- yes, that is an excellent description of the problem. > You don't ever want a class that has functions that need to be called in > a certain order to *not* crash. That's fine if you have to call them in > a certain sequence in order to get the correct data - that's what > programming is all about, after all. But if you provide me a class with > a constructor you better make sure that when I do this: > > thing = YourSuperAwesomeClass() > thing.do_stuff() > > that I don't get some horrid stack trace ending with > > InvalidStateError: initialize() needs to be called before > do_stuff() > > Or something worse. Exactly. Thank you Wayne, that's a great help. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2013-05-10 11:43 +1200 |
| Message-ID | <av2qleF58afU1@mid.individual.net> |
| In reply to | #45024 |
Wayne Werner wrote:
> You don't ever want a class that has functions that need to be called in
> a certain order to *not* crash.
That seems like an overly broad statement. What
do you think the following should do?
f = open("myfile.dat")
f.close()
data = f.read()
--
Greg
[toc] | [prev] | [next] | [standalone]
| From | Michael Speer <knomenet@gmail.com> |
|---|---|
| Date | 2013-05-09 20:18 -0400 |
| Message-ID | <mailman.1514.1368145123.3114.python-list@python.org> |
| In reply to | #45065 |
[Multipart message — attachments visible in raw view] — view raw
By his reasoning it simply shouldn't exist. Instead you would access the
information only like this:
with open("myfile.dat") as f:
data = f.read()
Which is my preferred way to work with resources requiring cleanup in
python anyways, as it ensures I have the least chance of messing things up,
and that all of my resources are disposed of properly during the unwind.
It's a hell of a lot cleaner than remembering to call the appropriate
cleanup functions at every callsite, and the resultant values can never be
in a bad state ( at least due to programmer function-ordering fault,
underlying file i/o errors and things can still cause errors, but not due
to API mis-usage ).
Python 3's multiple-with-statement-target syntax was backported to 2.7 as
well, flattening the deep nests of with statements otherwise needed to
implement this pattern
http://docs.python.org/dev/whatsnew/2.7.html#other-language-changes
On Thu, May 9, 2013 at 7:43 PM, Gregory Ewing
<greg.ewing@canterbury.ac.nz>wrote:
> Wayne Werner wrote:
>
>> You don't ever want a class that has functions that need to be called in
>> a certain order to *not* crash.
>>
>
> That seems like an overly broad statement. What
> do you think the following should do?
>
> f = open("myfile.dat")
> f.close()
> data = f.read()
>
>
> --
> Greg
> --
> http://mail.python.org/**mailman/listinfo/python-list<http://mail.python.org/mailman/listinfo/python-list>
>
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-05-09 20:50 -0400 |
| Message-ID | <roy-FA6CCF.20501509052013@news.panix.com> |
| In reply to | #45070 |
In article <mailman.1514.1368145123.3114.python-list@python.org>,
Michael Speer <knomenet@gmail.com> wrote:
> By his reasoning it simply shouldn't exist. Instead you would access the
> information only like this:
>
> with open("myfile.dat") as f:
> data = f.read()
The problem with things like file objects is they model external
real-world entities, which have externally-imposed real-world behaviors.
f.close() can fail, most commonly because some buffered output couldn't
be written when being flushed as part of the close(). Sometimes it's
important to find out about that.
[toc] | [prev] | [next] | [standalone]
| From | Wayne Werner <wayne@waynewerner.com> |
|---|---|
| Date | 2013-05-12 12:14 -0500 |
| Message-ID | <mailman.1587.1368378911.3114.python-list@python.org> |
| In reply to | #45065 |
On Fri, 10 May 2013, Gregory Ewing wrote:
> Wayne Werner wrote:
>> You don't ever want a class that has functions that need to be called in a
>> certain order to *not* crash.
>
> That seems like an overly broad statement. What
> do you think the following should do?
>
> f = open("myfile.dat")
> f.close()
> data = f.read()
To clarify - you don't want a class that has functions that need to be
called in a certain order with *valid input* in order to not crash.
Exactly what does happen - a ValueError is raised because you're(*)
passing self into the file.read() function, and that input is invalid
input - specifically:
ValueError: I/O operation on closed file
*where you actually means python, because when you call
`your_instance.method()`, it works effectively like a call to
`YourClass.method(your_instance)`
-W
[toc] | [prev] | [next] | [standalone]
| From | Terry Jan Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2013-05-12 16:03 -0400 |
| Message-ID | <mailman.1594.1368389026.3114.python-list@python.org> |
| In reply to | #45065 |
On 5/12/2013 1:14 PM, Wayne Werner wrote:
> On Fri, 10 May 2013, Gregory Ewing wrote:
>
>> Wayne Werner wrote:
>>> You don't ever want a class that has functions that need to be called
>>> in a certain order to *not* crash.
>>
>> That seems like an overly broad statement. What
>> do you think the following should do?
>>
>> f = open("myfile.dat")
>> f.close()
>> data = f.read()
>
> To clarify - you don't want a class that has functions that need to be
> called in a certain order with *valid input* in order to not crash.
>
> Exactly what does happen - a ValueError is raised because you're(*)
> passing self into the file.read() function, and that input is invalid
> input - specifically:
>
> ValueError: I/O operation on closed file
>
> *where you actually means python, because when you call
> `your_instance.method()`, it works effectively like a call to
> `YourClass.method(your_instance)`
The new idiom
with open("myfile.dat") as f:
data = f.read()
partially encapsulates operations on the opened file before the
automatic close. It is true however, that after the with statement, f in
still uselessly bound to the closed file. (Well, you can check the mode,
encoding, and other attributes, so not totally useless.) To completely
encapsulate, one can end the block with 'del f'. I checked and this
works. Since the external 'as x' name binding is optional, an internal
reference to the context manager (the io.xxx instance) is kept in order
to call the __exit__ method, and that is not affected by deleting the
optional visible binding.
tjr
[toc] | [prev] | [next] | [standalone]
| From | Greg Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2013-05-13 11:18 +1200 |
| Message-ID | <mailman.1602.1368400703.3114.python-list@python.org> |
| In reply to | #45065 |
Wayne Werner wrote:
> On Fri, 10 May 2013, Gregory Ewing wrote:
>
>> f = open("myfile.dat")
>> f.close()
>> data = f.read()
>
> To clarify - you don't want a class that has functions that need to be
> called in a certain order with *valid input* in order to not crash.
>
> Exactly what does happen - a ValueError is raised because you're(*)
> passing self into the file.read() function, and that input is invalid
The same argument can be applied to:
foo = Foo()
foo.do_something()
foo.enable() # should have done this first
You're passing an invalid input to Foo.do_something,
namely a Foo that hasn't been enabled yet.
--
Greg
[toc] | [prev] | [next] | [standalone]
| From | Fábio Santos <fabiosantosart@gmail.com> |
|---|---|
| Date | 2013-05-13 07:32 +0100 |
| Message-ID | <mailman.1609.1368426760.3114.python-list@python.org> |
| In reply to | #45065 |
[Multipart message — attachments visible in raw view] — view raw
On 13 May 2013 00:22, "Greg Ewing" <greg.ewing@canterbury.ac.nz> wrote:
>
> Wayne Werner wrote:
>>
>> On Fri, 10 May 2013, Gregory Ewing wrote:
>>
>>> f = open("myfile.dat")
>>> f.close()
>>> data = f.read()
>>
>>
>> To clarify - you don't want a class that has functions that need to be
called in a certain order with *valid input* in order to not crash.
>>
>> Exactly what does happen - a ValueError is raised because you're(*)
passing self into the file.read() function, and that input is invalid
>
>
> The same argument can be applied to:
>
> foo = Foo()
> foo.do_something()
> foo.enable() # should have done this first
>
> You're passing an invalid input to Foo.do_something,
> namely a Foo that hasn't been enabled yet.
>
>
> --
> Greg
> --
> http://mail.python.org/mailman/listinfo/python-list
I don't think you can really count that as invalid input in OOP terms.
After all in most languages `self` / `this` / whatever is not an argument
to every method.
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-05-13 17:36 +1000 |
| Message-ID | <mailman.1612.1368430610.3114.python-list@python.org> |
| In reply to | #45065 |
On Mon, May 13, 2013 at 4:32 PM, Fábio Santos <fabiosantosart@gmail.com> wrote: > > On 13 May 2013 00:22, "Greg Ewing" <greg.ewing@canterbury.ac.nz> wrote: >> The same argument can be applied to: >> >> foo = Foo() >> foo.do_something() >> foo.enable() # should have done this first >> >> You're passing an invalid input to Foo.do_something, >> namely a Foo that hasn't been enabled yet. > > I don't think you can really count that as invalid input in OOP terms. After > all in most languages `self` / `this` / whatever is not an argument to every > method. Yes, it is; it's just often implicit. C++ lets you poke around with the internals, and it's pretty clear that 'this' is an argument. (See for instance what happens with the gcc 'format' attribute - I can't find a convenient docs page, but it's been mentioned on SO [1] and can be easily verified.) EMCAScript lets you call any function with any 'this' by using the .call() or .apply() methods - which, in my extremely not-humble opinionated opinion, is bad design (closures work implicitly, but the 'this' pointer doesn't??). Python turns an attribute lookup on an instance into an attribute lookup on the class plus a currying. One way or another, the bit-before-the-dot is an argument to the function. [1] http://stackoverflow.com/questions/11621043/how-should-i-properly-use-attribute-format-printf-x-y-inside-a-class ChrisA
[toc] | [prev] | [next] | [standalone]
Page 4 of 5 — ← Prev page 1 2 3 [4] 5 Next page →
Back to top | Article view | comp.lang.python
csiph-web