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 1 of 5 [1] 2 3 4 5 Next page →
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-08 08:52 +0000 |
| Subject | object.enable() anti-pattern |
| Message-ID | <518a123c$0$11094$c3e8da3@news.astraweb.com> |
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:
f = file("some_file.txt")
f.open()
data = f.read()
because reading the file can fail if you forget to call open first.
Instead, Python uses a factory function that creates the file object and
opens it:
f = open("some_file.txt") # if this succeeds, f is ready to use
data = f.read()
Basically, any time you have two steps required for using an object, e.g.
like this:
obj = someobject(arg1, arg2)
obj.enable()
you should move the make-it-work functionality out of the enable method
and into __init__ so that creating the object creates it in a state ready
to work.
I read a blog some time ago (a year ago?) that discusses this anti-
pattern, and I'm pretty sure gave it a specific name, but I cannot find
it again. Can anyone find any references to this anti-pattern? My google-
fu is letting me down.
(For what it's worth, I'm refactoring some of my own code that falls into
this anti-pattern. Die, enable method, die die die!)
--
Steven
[toc] | [next] | [standalone]
| From | Christian Heimes <christian@python.org> |
|---|---|
| Date | 2013-05-08 11:51 +0200 |
| Message-ID | <mailman.1446.1368006720.3114.python-list@python.org> |
| In reply to | #44944 |
Am 08.05.2013 10:52, schrieb Steven D'Aprano:
> Basically, any time you have two steps required for using an object, e.g.
> like this:
>
> obj = someobject(arg1, arg2)
> obj.enable()
>
> you should move the make-it-work functionality out of the enable method
> and into __init__ so that creating the object creates it in a state ready
> to work.
In general I agree that an object.enable() function is ugly. ;)
But it's not necessarily the best solution for all problems. If the
resource needs some kind of cleanup, the context api (__enter__() /
__exit__()) is perfectly fine way to enable and disable the object.
For example:
class MyFile:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.open()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
I suggest that you mention the context API in your blog post, too.
Christian
[toc] | [prev] | [next] | [standalone]
| From | Robert Kern <robert.kern@gmail.com> |
|---|---|
| Date | 2013-05-08 11:13 +0100 |
| Message-ID | <mailman.1448.1368008024.3114.python-list@python.org> |
| In reply to | #44944 |
On 2013-05-08 09:52, 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. I don't think the anti-pattern has a name, but it's opposite pattern is named: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-08 12:30 +0000 |
| Message-ID | <518a4566$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #44948 |
On Wed, 08 May 2013 11:13:33 +0100, Robert Kern wrote: > On 2013-05-08 09:52, 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. > > I don't think the anti-pattern has a name, but it's opposite pattern is > named: > > http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization That sounds like it should be related, but it actually isn't since RAII actually has little to do with *acquiring* the resource and everything to do with *releasing* it. See, for example: http://stackoverflow.com/questions/2321511/what-is-meant-by-resource- acquisition-is-initialization-raii where it is pointed out that the resource may be acquired outside of the object constructor and passed in as an argument. RAII is actually about deterministic destruction of objects and the release of their resources. But thanks for the attempt :-) -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-05-08 09:17 -0400 |
| Message-ID | <roy-B0966A.09171708052013@news.panix.com> |
| In reply to | #44944 |
In article <518a123c$0$11094$c3e8da3@news.astraweb.com>,
Steven D'Aprano <steve+comp.lang.python@pearwood.info> 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:
>
>
> f = file("some_file.txt")
> f.open()
> data = f.read()
I've worked with C++ code that did this. At one point in the evolution
of OOP group consciousness, there was a feeling that constructors must
never fail. I don't remember if it was a general language-agnostic
pattern, or a specific C++ reaction to poor exception handling code in
early compilers. What came out of that was the pattern you describe.
All the code that could fail was factored out of the constructor into an
"enable" method.
That being said, sometimes there are good reasons for doing this. One
example might be something like:
frobnicator = Frobnicator()
for file in my_file_list:
frobnicator.munch(file)
for line in frobnicator:
process(line)
If creating a Frobnicator instance is very expensive, it might pay to
create an instance once and keep reusing it on multiple files. Here,
munch() is your enable() method. But, that's not quite what you were
talking about.
[toc] | [prev] | [next] | [standalone]
| From | Duncan Booth <duncan.booth@invalid.invalid> |
|---|---|
| Date | 2013-05-08 14:27 +0000 |
| Message-ID | <XnsA1BA9D45BE58Cduncanbooth@127.0.0.1> |
| In reply to | #44944 |
Steven D'Aprano <steve+comp.lang.python@pearwood.info> 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 I've come across this under the name 'two-phase construction', but as a desirable(!?) pattern rathern than as an anti-pattern. In particular Symbian used it throughout as originally their C++ implementation didn't support exceptions. Instead they had a separate cleanup stack and objects that require cleanup were pushed onto that stack after being fully constructed but before calling the initialisation that required cleanup. See http://www.developer.nokia.com/Community/Wiki/Two-phase_construction -- Duncan Booth
[toc] | [prev] | [next] | [standalone]
| From | Dan Sommers <dan@tombstonezero.net> |
|---|---|
| Date | 2013-05-09 02:38 +0000 |
| Message-ID | <M_Dit.288$oB7.229@newsfe02.iad> |
| In reply to | #44954 |
On Wed, 08 May 2013 14:27:53 +0000, Duncan Booth wrote: > Steven D'Aprano <steve+comp.lang.python@pearwood.info> 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 > > I've come across this under the name 'two-phase construction', but as > a desirable(!?) pattern rathern than as an anti-pattern. Think of spinning off a thread: initialize it synchronously, and then let it execute asynchronously. We tend towards that pattern even when we know that execution will be synchronous, because we also that it could be asynchronous one day. Yes, we could wrap that up in a neat bundle, but explicit is better than implicit. Dan
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-09 05:37 +0000 |
| Message-ID | <518b361f$0$11120$c3e8da3@news.astraweb.com> |
| In reply to | #44992 |
On Thu, 09 May 2013 02:38:36 +0000, Dan Sommers wrote:
> Think of spinning off a thread: initialize it synchronously, and then
> let it execute asynchronously. We tend towards that pattern even when
> we know that execution will be synchronous, because we also that it
> could be asynchronous one day.
Whether it is synchronous or asynchronous is irrelevant.
I can see use-cases for separating "make it go" from initialisation. It
all depends on what you might want to do to the object before making it
go. If the answer is "Nothing", then there is no reason not to have the
constructor make it go. If the answer is, "Well, sometimes we need to do
things to the object before making it go", then it makes sense to
separate the two:
blob = MyBlob(arg1, arg2, agr3)
blob.poke("with a stick")
blob.append(data)
blob.foo = "spam"
blob.make_it_go()
I'm not talking about this case. I'm talking about the case where there's
nothing you can do with the blob before making it go.
> Yes, we could wrap that up in a neat
> bundle, but explicit is better than implicit.
"And that is why we always write code like this:
n = int(int(len(something)) + int(1))
just to be sure that the result is explicitly an int and not just
implicitly an int. Suppose some Javascript programmer was reading the
code, and they thought that 1 was a floating point value. That would be
bad!"
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2013-05-09 15:52 +1000 |
| Message-ID | <mailman.1479.1368078731.3114.python-list@python.org> |
| In reply to | #45003 |
On Thu, May 9, 2013 at 3:37 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> I can see use-cases for separating "make it go" from initialisation. It
> all depends on what you might want to do to the object before making it
> go. If the answer is "Nothing", then there is no reason not to have the
> constructor make it go. If the answer is, "Well, sometimes we need to do
> things to the object before making it go", then it makes sense to
> separate the two:
>
> blob = MyBlob(arg1, arg2, agr3)
> blob.poke("with a stick")
> blob.append(data)
> blob.foo = "spam"
> blob.make_it_go()
Example use-case: Most GUI frameworks. You create a window, then
populate it, then show it. When you create the window object in
Python, you expect an actual window to exist, it should have its
handle etc. So it's still the same thing; the object is fully created
in its constructor.
ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-09 03:12 +0000 |
| Message-ID | <518b1409$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #44954 |
On Wed, 08 May 2013 14:27:53 +0000, Duncan Booth wrote: > Steven D'Aprano <steve+comp.lang.python@pearwood.info> 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 > > I've come across this under the name 'two-phase construction', but as a > desirable(!?) pattern rathern than as an anti-pattern. > > In particular Symbian used it throughout as originally their C++ > implementation didn't support exceptions. Instead they had a separate > cleanup stack and objects that require cleanup were pushed onto that > stack after being fully constructed but before calling the > initialisation that required cleanup. See > http://www.developer.nokia.com/Community/Wiki/Two-phase_construction Thanks for the link. It's obviously not the blog post I was looking for, but it is interesting. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Dan Sommers <dan@tombstonezero.net> |
|---|---|
| Date | 2013-05-09 02:42 +0000 |
| Message-ID | <Z1Eit.289$oB7.283@newsfe02.iad> |
| In reply to | #44944 |
On Wed, 08 May 2013 08:52:12 +0000, Steven D'Aprano wrote:
> 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:
>
> f = file("some_file.txt")
> f.open()
> data = f.read()
So why don't we do this?
data = read("some_file.txt")
> because reading the file can fail if you forget to call open first.
> Instead, Python uses a factory function that creates the file object and
> opens it:
>
> f = open("some_file.txt") # if this succeeds, f is ready to use
> data = f.read()
That's just the "enable" paradigm in a socially acceptable and
traditional wrapper.
Opening and closing the file is an implementation detail, often defeated
by caching (application level or OS level) anyway.
Dan
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-09 05:23 +0000 |
| Message-ID | <518b32ef$0$11120$c3e8da3@news.astraweb.com> |
| In reply to | #44993 |
On Thu, 09 May 2013 02:42:01 +0000, Dan Sommers wrote:
> On Wed, 08 May 2013 08:52:12 +0000, Steven D'Aprano wrote:
>
>> 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:
>>
>> f = file("some_file.txt")
>> f.open()
>> data = f.read()
>
> So why don't we do this?
>
> data = read("some_file.txt")
Because there is a lot more that you might want to do to a file than just
read from it.
py> f = open('/tmp/x')
py> dir(f)
['_CHUNK_SIZE', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__',
'__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__',
'__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', '_checkClosed', '_checkReadable',
'_checkSeekable', '_checkWritable', 'buffer', 'close', 'closed',
'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty',
'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable',
'readline', 'readlines', 'seek', 'seekable', 'tell', 'truncate',
'writable', 'write', 'writelines']
That's 24 public methods and attributes, excluding private and dunder
attributes.
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?
Besides, this is not to denigrate the idea of a read() function that
takes a filename and returns its contents. But that is not an object
constructor. It may construct a file object internally, but it doesn't
return the file object, so it is completely unrelated to the scenario I
described.
>> because reading the file can fail if you forget to call open first.
>> Instead, Python uses a factory function that creates the file object
>> and opens it:
>>
>> f = open("some_file.txt") # if this succeeds, f is ready to use
>> data = f.read()
>
> That's just the "enable" paradigm in a socially acceptable and
> traditional wrapper.
Well duh. That's like saying that for loops, while loops and co-routines
are just GOTO in a socially acceptable and traditional wrapper. Of course
they are. That's the whole point.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Terry Jan Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2013-05-09 02:41 -0400 |
| Message-ID | <mailman.1481.1368081725.3114.python-list@python.org> |
| In reply to | #45002 |
On 5/9/2013 1:23 AM, Steven D'Aprano wrote: > Besides, this is not to denigrate the idea of a read() function that > takes a filename and returns its contents. But that is not an object > constructor. It may construct a file object internally, but it doesn't > return the file object, so it is completely unrelated to the scenario I > described. At least a few stdlib modules that define classes *also* have such functions. They create an instance of the class, call one or more methods, and return the result of the method, discarding the instance. For instance, see the subprocess module, its POpen class, and module functions; or the timeit module, its Timer class, and functions.
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2013-05-09 19:54 +1200 |
| Message-ID | <av132gFneo2U1@mid.individual.net> |
| In reply to | #45002 |
Steven D'Aprano wrote: > There is no sensible use-case for creating a file without opening it. > What would be the point? Early unix systems often used this as a form of locking. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Cameron Simpson <cs@zip.com.au> |
|---|---|
| Date | 2013-05-09 18:23 +1000 |
| Message-ID | <mailman.1488.1368087823.3114.python-list@python.org> |
| In reply to | #45014 |
On 09May2013 19:54, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: | Steven D'Aprano wrote: | >There is no sensible use-case for creating a file without opening | >it. What would be the point? | | Early unix systems often used this as a form of locking. Not just early systems: it's a nice lightweight method of making a lockfile even today if you expect to work over NFS, where not that many things are synchronous. You open a file with "0" modes, so that it is _immediately_ not writable. Other attempts to make the lock file thus fail because of the lack of write, even over NFS. Cheers, -- Cameron Simpson <cs@zip.com.au> You can listen to what everybody says, but the fact remains that you've got to get out there and do the thing yourself. - Joan Sutherland
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-09 11:30 +0000 |
| Message-ID | <518b88d8$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #45019 |
On Thu, 09 May 2013 18:23:31 +1000, Cameron Simpson wrote: > On 09May2013 19:54, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: > | Steven D'Aprano wrote: > | > There is no sensible use-case for creating a file WITHOUT OPENING > | > it. What would be the point? > | > | Early unix systems often used this as a form of locking. > > Not just early systems: it's a nice lightweight method of making a > lockfile even today if you expect to work over NFS, where not that many > things are synchronous. You OPEN A FILE with "0" modes [emphasis added] This is all very well and good, but for the life of me, I cannot see how opening a file is a good example of not opening a file. Perhaps it is a Zen thing, like the sound no spoon makes when you don't tap it against a glass that isn't there. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Cameron Simpson <cs@zip.com.au> |
|---|---|
| Date | 2013-05-10 09:36 +1000 |
| Message-ID | <mailman.1512.1368142627.3114.python-list@python.org> |
| In reply to | #45027 |
On 09May2013 11:30, Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: | On Thu, 09 May 2013 18:23:31 +1000, Cameron Simpson wrote: | | > On 09May2013 19:54, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: | > | Steven D'Aprano wrote: | > | > There is no sensible use-case for creating a file WITHOUT OPENING | > | > it. What would be the point? | > | | > | Early unix systems often used this as a form of locking. | > | > Not just early systems: it's a nice lightweight method of making a | > lockfile even today if you expect to work over NFS, where not that many | > things are synchronous. You OPEN A FILE with "0" modes | | [emphasis added] | This is all very well and good, but for the life of me, I cannot see how | opening a file is a good example of not opening a file. Perhaps it is a | Zen thing, like the sound no spoon makes when you don't tap it against a | glass that isn't there. Because a file usually does not exist in isolation (yes sometimes we want an isolated file). Files usually exist in the filesystem, which is a namespace. And this is effectively a namespace operation, not a data storage operation. Of course, I can take this the other way: just because I opened it with a 0 mode field doesn't mean _I_, the opener, cannot read/write it. I've got an open file handle... A race free way to make a scratch file in a shared area, for example. The point is probably that a file isn't merely a feature free byte storage container; in the real world they usually come with all sorts of features like names and permissions. Those features will always imply creative uses. Anyway, this has little to do with your antipattern (about which I'm not totally convinced anyway unless it is a rule of thumb or code smell). It might apply to a Platonicly ideal file, but real files have more than one use case. Cheers, -- Cameron Simpson <cs@zip.com.au> I just kept it wide-open thinking it would correct itself. Then I ran out of talent. - C. Fittipaldi
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-10 05:00 +0000 |
| Message-ID | <518c7f05$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #45064 |
On Fri, 10 May 2013 09:36:43 +1000, Cameron Simpson wrote: > On 09May2013 11:30, Steven D'Aprano > <steve+comp.lang.python@pearwood.info> wrote: > | On Thu, 09 May 2013 18:23:31 +1000, Cameron Simpson wrote: > | > | > On 09May2013 19:54, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote: > | > | Steven D'Aprano wrote: > | > | > There is no sensible use-case for creating a file WITHOUT > | > | > OPENING it. What would be the point? > | > | > | > | Early unix systems often used this as a form of locking. > | > > | > Not just early systems: it's a nice lightweight method of making a > | > lockfile even today if you expect to work over NFS, where not that > | > many things are synchronous. You OPEN A FILE with "0" modes > | [emphasis added] > > | This is all very well and good, but for the life of me, I cannot see > | how opening a file is a good example of not opening a file. Perhaps it > | is a Zen thing, like the sound no spoon makes when you don't tap it > | against a glass that isn't there. > > Because a file usually does not exist in isolation (yes sometimes we > want an isolated file). Files usually exist in the filesystem, which is > a namespace. And this is effectively a namespace operation, not a data > storage operation. > > Of course, I can take this the other way: just because I opened it with > a 0 mode field doesn't mean _I_, the opener, cannot read/write it. I've > got an open file handle... A race free way to make a scratch file in a > shared area, for example. But you are opening the file. Therefore, it cannot possibly be an example of not opening the file. Unlike Pascal, there is no way to create a C file descriptor in a closed state. Such a thing does not exist. If you have a file descriptor, the file is open. Once you close it, the file descriptor is no longer valid. But even if C allowed you to do so, doesn't mean that it is a good idea. At least some variants of Pascal force you to do the following: # Pseudo-code. f = open(filename) really_open(f) data = read(f) # or write, or *any other operation at all* Surely we can agree that having to call both open() and really_open() before you get an actually opened file that you can use is one call too many? There is *nothing* you can do with f before calling really_open(). So why require it? (For the record, "really_open" is spelled "reset" or "rewrite" depending on whether you want to read or write to the file.) > The point is probably that a file isn't merely a feature free byte > storage container; in the real world they usually come with all sorts of > features like names and permissions. Those features will always imply > creative uses. There are at least three related but separate things here. * file objects, or their low-level equivalent, file descriptors; * pathnames; * files on disk, which are an abstraction for data in a particular kind of data structure. They are obviously related, but they are also obviously independent. You can have a pathname that doesn't refer to any file on disk; you can have a file on disk that has been lost, and therefore is no longer accessible via a file name. (If you run fsck or equivalent, the file may be recoverable, but the name will be lost.) You can open a file object, then unlink it so it no longer points to a file on disk, but does still accept read or write calls. The counter-examples given so far apply to pathnames or files on disk. They don't apply to file objects and file descriptors. I have tried really hard to be clear that I am talking about file objects. To the extent that I have failed, I am sorry. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Roy Smith <roy@panix.com> |
|---|---|
| Date | 2013-05-10 01:50 -0400 |
| Message-ID | <roy-7584FC.01500910052013@news.panix.com> |
| In reply to | #45083 |
In article <518c7f05$0$29997$c3e8da3$5496439d@news.astraweb.com>,
Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote:
> there is no way to create a C file descriptor in a closed state. Such
> a thing does not exist. If you have a file descriptor, the file is
> open. Once you close it, the file descriptor is no longer valid.
Of course there is.
int fd = 37;
I've just created a file descriptor. There is not enough information
given to know if it corresponds to an open file or not.
Before you protest that "it's just an int, not a file descriptor", I
should point out that they're the same thing. It's pretty common to do
something like:
for (int fd = 0; fd <= MAX_FD; fd++) {
close(fd)
}
before forking, to make sure all file descriptors are closed.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2013-05-10 09:47 +0000 |
| Message-ID | <518cc239$0$29997$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #45085 |
On Fri, 10 May 2013 01:50:09 -0400, Roy Smith wrote: > In article <518c7f05$0$29997$c3e8da3$5496439d@news.astraweb.com>, > Steven D'Aprano <steve+comp.lang.python@pearwood.info> wrote: > >> there is no way to create a C file descriptor in a closed state. Such a >> thing does not exist. If you have a file descriptor, the file is open. >> Once you close it, the file descriptor is no longer valid. > > Of course there is. > > int fd = 37; > > I've just created a file descriptor. There is not enough information > given to know if it corresponds to an open file or not. No, you haven't created a file descriptor. You've made up a number which C will allow you to use as an index into the file descriptor table, because C is a high-level assembler with very little in the way of type safety, and what little there is you can normally bypass. What you haven't done is create the record in the file descriptor table. You can't expect that read(fd) or write(fd) will work, although both should fail safe rather than segfault if 37 happens to not be an actual file descriptor. What you've done is the moral equivalent of choosing an integer at random, coercing it to a pointer, then dereferencing it to peek or poke at some memory address. (Although fortunately much safer.) It's a nice hack, but not one that takes away from what I'm saying. -- Steven
[toc] | [prev] | [next] | [standalone]
Page 1 of 5 [1] 2 3 4 5 Next page →
Back to top | Article view | comp.lang.python
csiph-web