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


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

object.enable() anti-pattern

Started bySteven D'Aprano <steve+comp.lang.python@pearwood.info>
First post2013-05-08 08:52 +0000
Last post2013-05-13 08:15 -0500
Articles 20 on this page of 82 — 23 participants

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


Contents

  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 →


#45136

FromMark Janssen <dreamingforward@gmail.com>
Date2013-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]


#45076

FromChris Angelico <rosuav@gmail.com>
Date2013-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]


#45054

Fromroy@panix.com (Roy Smith)
Date2013-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]


#45058

FromChris Angelico <rosuav@gmail.com>
Date2013-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]


#45115

FromNobody <nobody@nowhere.com>
Date2013-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]


#45119

FromRoy Smith <roy@panix.com>
Date2013-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]


#45147

FromDennis Lee Bieber <wlfraed@ix.netcom.com>
Date2013-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]


#45127

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-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]


#44994

FromMark Janssen <dreamingforward@gmail.com>
Date2013-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]


#44995

FromMark Janssen <dreamingforward@gmail.com>
Date2013-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]


#45024

FromWayne Werner <wayne@waynewerner.com>
Date2013-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]


#45028

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-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]


#45065

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2013-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]


#45070

FromMichael Speer <knomenet@gmail.com>
Date2013-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]


#45071

FromRoy Smith <roy@panix.com>
Date2013-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]


#45190

FromWayne Werner <wayne@waynewerner.com>
Date2013-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]


#45199

FromTerry Jan Reedy <tjreedy@udel.edu>
Date2013-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]


#45209

FromGreg Ewing <greg.ewing@canterbury.ac.nz>
Date2013-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]


#45222

FromFábio Santos <fabiosantosart@gmail.com>
Date2013-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]


#45226

FromChris Angelico <rosuav@gmail.com>
Date2013-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