I just stared at this a long time:
'a' in 'a' # fine 1 'a' in 'a' == 1 # what? 0 'a' in 'b' # fine 0 'a' in 'b' == 0 # what? 0
It's "correct". I've been using Python longer than Guido <wink>, and I'm amazed this is the first time I got bit by this! Here's a hint:
'a' in 'a' == 'a' 1
thank-god-for-dis.dis-ly y'rs - tim
Tim Peters wrote:
...
'a' in 'a' == 'a' 1
thank-god-for-dis.dis-ly y'rs - tim
[potential spoilers below] No, thank Jeremy for Compiler: Module(None, Stmt( [ Printnl( [ Compare(Const('a'), [ ('in', Const('abcde')), ('==', Const('abcde')) ] ) ], None ) ] ) ) It still took a look at the ref manual for me to figure it out. It looks like dubious hypergeneralization to me! <0.7 wink> Seriously, does this "feature" ever make sense to apply to the in operator? -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook
I just stared at this a long time:
'a' in 'a' # fine 1 'a' in 'a' == 1 # what? 0 'a' in 'b' # fine 0 'a' in 'b' == 0 # what? 0
It's "correct". I've been using Python longer than Guido <wink>, and I'm amazed this is the first time I got bit by this! Here's a hint:
'a' in 'a' == 'a' 1
thank-god-for-dis.dis-ly y'rs - tim
Yeah, I ran into the same when converting some has_key() tests to using 'in'. I guess it's not very common since nobody in their right minds should want to compare the result of an 'in' test to anything else. The has_key() tests did something like "assert d.has_key(k)==1" and the mindless translation of that is "assert k in d == 1"... Didn't-need-dis-though-ly y'rs, --Guido van Rossum (home page: http://www.python.org/~guido/)
"TP" == Tim Peters <tim.one@home.com> writes:
TP> It's "correct". I've been using Python longer than Guido TP> <wink>, and I'm amazed this is the first time I got bit by TP> this! Here's a hint: Oh, that is twisted! :) Let's throw in some parentheses just to confuse people even more:
'a' in 'a' == 'a' 1 ('a' in 'a') == 'a' 0 'a' in ('a' == 'a') Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: 'in' or 'not in' needs sequence right argument 'a' in 'a' == 1 0 ('a' in 'a') == 1 1 'a' in ('a' == 1) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: 'in' or 'not in' needs sequence right argument
"PP" == Paul Prescod <paulp@ActiveState.com> writes:
PP> It looks like dubious hypergeneralization to me! <0.7 wink> PP> Seriously, does this "feature" ever make sense to apply to the PP> in operator? I don't know; I wonder if "normal" people think of `in' as a chainable comparison operator or not. You're not suggesting to change this are you? gotta-leave-something-`in'-there-for-job-security-ly y'rs, -Barry
"TP" == Tim Peters <tim.one@home.com> writes:
TP> It's "correct". I've been using Python longer than Guido TP> <wink>, and I'm amazed this is the first time I got bit by TP> this! Here's a hint:
[Barry]
Oh, that is twisted! :)
Let's throw in some parentheses just to confuse people even more: ... gotta-leave-something-`in'-there-for-job-security-ly y'rs,
You're safely employed for years:
'a' in 'abc' == 1 0 'a' in 'abc' == 'a' 0 'a' in 'abc' == 'a' in 'abc' 0
but-a-raise-is-out-of-the-question-ly y'rs - Gordon
[Tim, 'a' in 'a' == 1, etc] [Guido]
Yeah, I ran into the same when converting some has_key() tests to using 'in'.
Bingo! Same here, but after adding __iter__ and __contains__ to UserDict.py, then fiddling test_userdict.py to match.
I guess it's not very common since nobody in their right minds should want to compare the result of an 'in' test to anything else. The has_key() tests did something like "assert d.has_key(k)==1" and the mindless translation of that is "assert k in d == 1"...
You'd think so <wink>. It was subtler in the first I bumped into, translating something like assert d1.has_key(k) == d2.has_key(k) The problem in assert k in d1 == k in d2 is, I think, harder to spot. That is, you may well be in your right might if you want to compare the result of an 'in' test to the result of *another* 'in' test! Even stranger, assert k in d1 != k in d2 succeeds if and only if k is in both d1 and d2 (assuming d1 is a dict and k isn't). I'm going to use that a lot in my code, because it's one less character than typing assert k in d1 and k in d2 Heh heh. *something*-about-this-may-not-be-ideal-ly y'rs - tim
"Barry A. Warsaw" wrote:
...
"PP" == Paul Prescod <paulp@ActiveState.com> writes:
PP> It looks like dubious hypergeneralization to me! <0.7 wink> PP> Seriously, does this "feature" ever make sense to apply to the PP> in operator?
I don't know; I wonder if "normal" people think of `in' as a chainable comparison operator or not.
If Tim, Guido, you and I are so completely out of sync with normal people that they will immediately intuit what we had to think hard about, we're in deep doo-doo!
You're not suggesting to change this are you?
I suggest a compile-time warning and then eventually we would make "in" non-chainable. Perhaps it should even have a different precedence than the other comparison operators. Tim's example looks reasonable to me: assert k in d1 == k in d2 And it would never, ever make sense to say: assert k in (d1==k) in d2 So why not interpret it the way that any normal human would: assert (k in d1) == (k in d2) I think that this is a subtle flaw in Python that just took a long time to manifest itself... And what about "1 is None == 2 is None"? If you saw that in a program (last week!) what would you have expected it to evalute to? Precedence levels exist to make code easier to read! -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook
[Paul Prescod]
If Tim, Guido, you and I are so completely out of sync with normal people that they will immediately intuit what we had to think hard about, we're in deep doo-doo!
Na, we're not, they are: they're *never* gonna figure it out <wink>.
I suggest a compile-time warning and then eventually we would make "in" non-chainable.
An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
Perhaps it should even have a different precedence than the other comparison operators. Tim's example looks reasonable to me:
assert k in d1 == k in d2
It *used* to look reasonable to me too <wink>.
And it would never, ever make sense to say:
assert k in (d1==k) in d2
Thin ice, there. __eq__ and __contains__ are both user-definable now, and there is no limit to how perverse ex-APL'ers can get with this stuff.
So why not interpret it the way that any normal human would:
assert (k in d1) == (k in d2)
That sounds best to me, but may be too much a bother. For example, it's not a stretch at all anymore to believe that someone *is* using a in b in c now deliberately for its (a in b) and (b in c) meaning. Perfectly natural if, e.g., you use __contains__ to implement an "is subset of" relation. If we have to keep chaining for "in", then having two distinct levels of chaining operators is bound to harbor its own odd corners. x == y in d I have no idea what that *should* mean, but having gone thru recent related pain I'm very clear now on what it *does* mean.
I think that this is a subtle flaw in Python that just took a long time to manifest itself...
You can thank Digital Creations for that, too. They're keeping Guido so busy that he doesn't have enough time to cloud our minds anymore. Makes you wonder how many other surprises he's been hiding from us <wink>!
Tim Peters wrote:
...
I suggest a compile-time warning and then eventually we would make "in" non-chainable.
An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
??? My understanding was that __future__ was a way of sneaking in a cool feature earlier than it would have been possible to deploy it given strict gradual evolution contraints. But disallowing confusing uses of "in" is not a feature and nobody is in a big hurry to see it happen. I wouldn't mind waiting a year or two until everyone has had a chance to clean up their code.
... For example, it's not a stretch at all anymore to believe that someone *is* using
a in b in c
now deliberately for its
(a in b) and (b in c)
meaning. Perfectly natural if, e.g., you use __contains__ to implement an "is subset of" relation.
The following grammar would preserve it and outlaw confusing cases: comparison: in_comparison | is_comparison | math_comparison math_comparison: expr (math_comp_op expr)* in_comparison: expr ('in' | 'not' 'in' expr)* is_comparison: expr ('is' | 'is' 'not' expr)* math_comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!=' -- Take a recipe. Leave a recipe. Python Cookbook! http://www.ActiveState.com/pythoncookbook
An incompatible language change would, I think, need to go thru the __future__ (however spelled) business.
[Paul]
???
My understanding was that __future__ was a way of sneaking in a cool feature earlier than it would have been possible to deploy it given strict gradual evolution contraints.
That's not what PEP 236 says. __future__ is about *incompatible* language changes, period. "Cool" has nothing to do with it. If you're making something illegal that used to work, that's an incompatible change, and people get at least one release cycle in which it continues to work without change but with warnings. They can also ask for future behavior early via using an explicit future-statement in the module. Although in this case I guess the "future behavior" is just to turn the wng msg into a SyntaxError, in which case the __future__ machinery does seem like overkill.
But disallowing confusing uses of "in" is not a feature
PEP 236 is about incompatible changes, not features. It so happens that the first use (nested scopes) was a new feature that *could* break old code, so was both a new feature and an incompatible change.
and nobody is in a big hurry to see it happen. I wouldn't mind waiting a year or two until everyone has had a chance to clean up their code.
I'd rather not nag people at all if this is the only time it's come up in a decade <wink>. We've all got too much to do.
... The following grammar would preserve it [chaining "in"] and outlaw confusing cases:
comparison: in_comparison | is_comparison | math_comparison math_comparison: expr (math_comp_op expr)* in_comparison: expr ('in' | 'not' 'in' expr)* is_comparison: expr ('is' | 'is' 'not' expr)* math_comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='
Did you try that grammar? I'm skeptical that it works, since at first glance the comparison production appears to require arbitrary lookahead to determine which xxx_comparison case obtains. But if so, I'm sure it can be repaired. Whether it *should* be is a different matter I'll leave to Guido to Pronounce on.
On Sun, Apr 22, 2001 at 08:04:21PM -0700, Paul Prescod wrote:
The following grammar would preserve it and outlaw confusing cases:
comparison: in_comparison | is_comparison | math_comparison math_comparison: expr (math_comp_op expr)* in_comparison: expr ('in' | 'not' 'in' expr)* is_comparison: expr ('is' | 'is' 'not' expr)* math_comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='
Won't work. Python's parser can't handle it. I also don't think the grammar really matters that much -- it's the compiler that does the actual chaining, it could decide not to chain and force a specific order, if it really wanted to. And generate warnings and all that :) -- Thomas Wouters <thomas@xs4all.net> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
participants (6)
-
barry@digicool.com
-
Gordon McMillan
-
Guido van Rossum
-
Paul Prescod
-
Thomas Wouters
-
Tim Peters