M
MonkeeSage
More often and easier to implement than dict.has_key / get?
More -> Less
More often and easier to implement than dict.has_key / get?
More often and easier to implement than dict.has_key / get?
Uh, no. KeyError.
Agreed. but why implement a certain functionality in one place but leave
it out of another?
No, *less* often. That's the point -- it is fairly common for people to
want dictionary lookup to return a default value, but quite rare for them
to want sequence lookup to return a default value. A sequence with a
default value would be, in some sense, equivalent to an infinite list:
dict.get() doesn't raise KeyError. That's the whole point of get(), it
returns a default value instead of raising KeyError.
If you don't care enough to even make a formal feature
request, let alone a PEP, then why should people who care even less
actually write the code?
MonkeeSage said:With list.has_index() / get(), the following (pretty common I think)
idiom:
try:
data = some_unknown_seq[2]
except IndexError:
data = None
if data: ...
but "let's hypergeneralize and treat sequences and mappings as the same
thing" proposals are nothing new; a trip to the archives might be help-
ful.
No: you are proposing to add features to the sequence interface forMonkeeSage said:Huh? I don't want to treat sequences and mappings as the same thing.
I'm talking about adding two similar convenience methods for sequences
as already exist for mappings. That may make the two APIs closer, but
that's not necessarily a bad thing (think the square-bracket accessor).
Besides, has_index is sufficiently different already. If it's really a
problem, change get() to at() for sequences. seq.at(2).
So far the reasons offered against adding those convenience methods
are:
Reason: It's unnecessary / bloat.
- Then the same thing is true of the dict methods.
Well I certainly didn't find your last one particularly convincing: theReason: It's not useful.
- I know of several use cases and could probably find others.
I would argue exactly the opposite: the reason why they shouldn't beReason: It takes effort to implement it. Why don't you do it yourself
if it's such a great idea!
- Mabye I will. But that is only a reason why they aren't currently
implemented, not why they *shouldn't* be.
Reason: It makes sequences and mapping to much alike.
- Then change the names for the sequences methods.
That is to say, no good reason has been offered for why these methods
shouldn't be implemented.
MonkeeSage said:Huh? I don't want to treat sequences and mappings as the same thing.
I'm talking about adding two similar convenience methods for sequences
as already exist for mappings.
No: you are proposing to add features to the sequence interface for
which there are few demonstrable use cases.
Well I certainly didn't find your last one particularly convincing: the
attempt to reference a non-existent sequence member is almost always a
programming error.
I would argue exactly the opposite: the reason why they shouldn't be
implemented is because no good reason has been presented why they *should*.
Keep right on guessing.MonkeeSage said:No: you are proposing to add features to the sequence interface for
which there are few demonstrable use cases.
If I really wanted to find them, how many instances do you think I
could find [in the standard lib and community-respected third-party
libs] of sequence index checking like "if 2 < len(seq)" and / or
try-excepting like "try: seq[2] ..."? Judging by the fact that there
isn't any other way to *safely* handle dynamic sequences (esp.
sequences which grow based on side-effects which may or may not be
present, depending on the execution path through the code); I'd guess
the number is alot higher than you seem to think.
OK, so now we appear to be arguing about whether a feature should goUnless you are interacting with user input, or other anomalous data
source. And in that case you need to do explicit index checking or wrap
your code with a try...except; that or you need a convenience function
or method that implements a non-terminating exception, and you just
check for the exceptional case, like dictionaries have with get(). I
find the latter approach to be easier to read and write (see link
below), as well as understand.
Nope. In fact d.has_key(k) is a historical spelling, retained only forI would argue exactly the opposite: the reason why they shouldn't be
implemented is because no good reason has been presented why they *should*.
Pretend like there are no dict.has_key and dict.get methods. Can you
provide a good reason(s) why they should be implemented? Not necessity
-- since you can do the same thing more verbosely. Usefulness? --
Probably; but I think the list methods would also be useful (see
above). Succinctness [1]? -- The list methods have the same advantage.
Anything else?
[1] http://mail.python.org/pipermail/python-dev/1999-July/000594.html
The fact that nobody has listed the good reasons why I shouldn't try toI looked yesterday and only found a few posts. A couple involved
Marc-Andre Lemburg, and mxTools, where he has a get() function that
works for sequences and mappings; that's not what I'm suggesting.
However, I found one from 1997 where he mentioned a patch to python 1.5
which added list.get, but I couldn't find the patch or any discussion
of why it was (presumably) rejected. The only other post I found that
was relevant was one on the dev-python list (mentioned in the July 1-15
summery [1]). And the only thing mentioned there as a reason against it
is that "It encourages bad coding. You
shouldn't be searching lists and tuples like that unless you know what
you're doing." (Whatever that is supposed to mean!).
Just point me to the discussion where the good reasons (or any at all)
against my suggestion can be found and I'll be glad to read it. I
couldn't find it.
[1]
http://www.python.org/dev/summary/2006-07-01_2006-07-15/#adding-list-get-and-tuple-get
Nope. In fact d.has_key(k) is a historical spelling, retained only for
backwards compatibility, of k in dict. As to the d.get(k, default)
method I really don't see a compelling use case despite your
protestations, and I don't seem to be alone. Please feel free to start
recruiting support.
Keep right on guessing.
OK, so now we appear to be arguing about whether a feature should go
into Python because *you* find it to be easier to read and write. But I
don't see a groundswell of support from other readers saying "Wow, I've
always wanted to do it like that".
In fact d.has_key(k) is a historical spelling, retained only for
backwards compatibility, of k in dict. As to the d.get(k, default)
method I really don't see a compelling use case despite your
protestations, and I don't seem to be alone. Please feel free to start
recruiting support.
The fact that nobody has listed the good reasons why I shouldn't try to
make a computer from mouldy cheese doesn't make this a good idea.
But how do you handle the case of:
l = []
i = 10
l = l.get(i, 0) + 1
MonkeeSage said:Keep right on guessing.
I hope I'm not offending one whom I consider to be much more skilled
and versed than I am, not only in python, but in programming in
general; but I must say: it seems you are being rather obtuse here. I
think I laid out the principal clearly enough, and I know you have the
mental capacity to extrapolate from the principal to general use cases.
But even so, here is a simple use case from the standard library
(python 2.5 release source):
In Libs/site.py, lines 302-306:
try:
for i in range(lineno, lineno + self.MAXLINES):
print self.__lines
except IndexError:
break
With my proposal, that could be written as:
for i in range(lineno, lineno + self.MAXLINES):
if self.__lines.has_index(i):
print self.__lines
else:
break
Granted, in this particular case the amount of code is not reduced, but
(and I would hope you'd agree) the control flow is certainly easier to
follow.
OK, so now we appear to be arguing about whether a feature should go
into Python because *you* find it to be easier to read and write. But I
don't see a groundswell of support from other readers saying "Wow, I've
always wanted to do it like that".
*Someone* (other than me!) obviously found it nice to have the dict
convenience methods. As for garnishing support, I almost see that as
more of a cultural, rather than pragmatic issue. I.e., if it's not
there already, then it shouldn't be there: "what is is what should be".
Of course, consistently following that naive presumption would totally
stiffle *any* extension to python. However, (I think) I do understand
the psychology of the matter, and don't fault those who cannot see past
what already is (not meaning to implicate you or Fredrick or anyone
else -- the comment is innocent).
In fact d.has_key(k) is a historical spelling, retained only for
backwards compatibility, of k in dict. As to the d.get(k, default)
method I really don't see a compelling use case despite your
protestations, and I don't seem to be alone. Please feel free to start
recruiting support.
As I stated to another poster; I'm not really concerned with
implementation details, only with the presence or absence of
convenience methods. You can write "if k in d" as easily as "if index <
len(seq)". But semantically, they are similar enough, in my (admittedly
lowly) estimation, to desevere similar convenience methods.
The fact that nobody has listed the good reasons why I shouldn't try to
make a computer from mouldy cheese doesn't make this a good idea.
Heh. True. I didn't mean to imply that I was arguing from the negative.
I was only tring to shift the perspective to include the reasons for
the dict convenience methods. If C is good for A, and A is sufficiently
similar to B, then C is good for B. But if C is just crud, then forget
it all around.
But how do you handle the case of:
l = []
i = 10
l = l.get(i, 0) + 1
You don't; you just let the IndexError fall through. Same as a KeyError
for d[k]. My propopsal is in regard to convencience methods, not to
direct access.
Ps. Sorry if this comes through twice, Google is being wierd right now.
MonkeeSage said:But even so, here is a simple use case from the standard library
(python 2.5 release source):
In Libs/site.py, lines 302-306:
try:
for i in range(lineno, lineno + self.MAXLINES):
print self.__lines
except IndexError:
break
With my proposal, that could be written as:
for i in range(lineno, lineno + self.MAXLINES):
if self.__lines.has_index(i):
print self.__lines
else:
break
MonkeeSage said:In Libs/site.py, lines 302-306:
try:
for i in range(lineno, lineno + self.MAXLINES):
print self.__lines
except IndexError:
break
With my proposal, that could be written as:
for i in range(lineno, lineno + self.MAXLINES):
if self.__lines.has_index(i):
print self.__lines
else:
break
Granted, in this particular case the amount of code is not reduced, but
(and I would hope you'd agree) the control flow is certainly easier to
follow.
Terry said:Is there an outer loop being 'break'ed?
yes.
This break is swallowed by the for loop, so not exactly equivalent, I
think.
In any case, these are both clumsy and I believe I would instead
write something like
for i in range(lineno, len(self.__lines)):
print self.__lines
I think we'll just have to agree to differ in this repsecrt, as I don't
see your suggestions for extending the sequence API as particularly
helpful.
so to "improve" a piece of code that's been optimized for the common
case, you're adding an extra method call and a test to the inner loop?
and this because you think Python programmers don't understand try-
except statements ?
I think we can all safely ignore you now.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.