Re: [Python-Dev] misbehaving __contains__

2008-01-23 Thread tomer filiba
On Jan 23, 2008 3:19 AM, Raymond Hettinger <[EMAIL PROTECTED]> wrote:
> [Steven Bethard]
>
> >We've already lost this if anyone really wants to break it::
> >
> >>>> class C(object):
> >... def __iter__(self):
> >... return iter(xrange(3))
> >... def __contains__(self, item):
> >... return False
[snip]

> I'm more concerned about introducing an API where well-meaning attempts to 
> code a __contains__ override will implicitly shoot the toes off of client 
> code that innocently assumes a somewhat sensible invariant relation between 
> looping over elements in a container and those elements being in the 
> container.  The code for sets and frozensets makes that assumption, for 
> example.  And, when the code does break, the errors will be darned hard to 
> find.


well, i don't see how limiting __contains__ to returning booleans
solves the problem you mentioned. what you're talking about is
*semantics*, and that's always up to the programmer to get right.
allowing __contains__ to return a FooBar object won't change that a
bit -- but it will allow me to construct expression objects more
easily.

and, statements like

if x in y:
pass

will work as expected, assuming the object returned by
y.__contains__(x) has a proper __bool__/__nonzero__ method. we're just
deferring the type-cast to the point it's actually needed.

as per performance, i don't believe changing a slot method to return
PyObject* instead of int would change anything... am i wrong?



-tomer
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Raymond Hettinger
>> And, would we lose the nice relationship expressed by:
>>
>> for elem in container:
>> assert elem in container


[Steven Bethard]
>We've already lost this if anyone really wants to break it::
>
>>>> class C(object):
>... def __iter__(self):
>... return iter(xrange(3))
>... def __contains__(self, item):
>... return False

I think this is in the same category as writing a __hash__ that doens't match 
__eq__.  It is explicitly shooting yourself in the foot.  

I'm more concerned about introducing an API where well-meaning attempts to code 
a __contains__ override will implicitly shoot the toes off of client code that 
innocently assumes a somewhat sensible invariant relation between looping over 
elements in a container and those elements being in the container.  The code 
for sets and frozensets makes that assumption, for example.  And, when the code 
does break, the errors will be darned hard to find.


Raymond

___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Steven Bethard
On Jan 22, 2008 5:40 PM, Raymond Hettinger <[EMAIL PROTECTED]> wrote:
> [Daniel Stutzbach]
> > There are many places in the C implementation where a slot
> > returns an int rather than a PyObject.  There other replies
> > in this thread seem to support altering the signature of the
> > slot to return a PyObject. Is this setting a precedent that
> > _all_ slots should return a PyObject?
>
> I hope not.
[snip]
> And, would we lose the nice relationship expressed by:
>
> for elem in container:
> assert elem in container

We've already lost this if anyone really wants to break it::

>>> class C(object):
... def __iter__(self):
... return iter(xrange(3))
... def __contains__(self, item):
... return False
...
>>> c = C()
>>> for item in c:
... print item in c
...
False
False
False

Of course, anyone who decides to break their container classes in that
way is asking for trouble. ;-)

STeVe
-- 
I'm not *in*-sane. Indeed, I am so far *out* of sane that you appear a
tiny blip on the distant coast of sanity.
--- Bucky Katt, Get Fuzzy
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Raymond Hettinger
[Daniel Stutzbach]
> There are many places in the C implementation where a slot 
> returns an int rather than a PyObject.  There other replies 
> in this thread seem to support altering the signature of the 
> slot to return a PyObject. Is this setting a precedent that 
> _all_ slots should return a PyObject?

I hope not.

One cost of these hypergeneralizations is that it makes
Python slower.  

Also, it makes it harder to write code when you can no longer
count on simple predicates to return either True or False.


[tomer filiba]
> i see no reason it should behave differently than 
> __eq__ and the rest of comparison operators

The rest of the equality operators were a special case
to allow rich comparisons which were needed to implement
some vector arithmetic idioms.  

It was thought that those use case had enough benefit
to pay for the negative impacts:
* making the language more complex
* slowing everything down a bit.
* complicating the underlying implementation
* making the language more difficult to learn (rich operators
are harder than cmp)

Does making __contains__ return a PyObject have use cases
that are worth those costs?  

It is reminiscent of the ill-fated proposals to overrride 'and',
'or', 'is', and 'is not'.
A couple more questions about the proposal: 

If __contains__ returns 17 in Tomer's example,
what would "8 not in f" return?   

And, would we lose the nice relationship expressed by:

for elem in container:
assert elem in container

It looks like changing the semantics would introduce some weirdness.


Raymond
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Guido van Rossum
On Jan 22, 2008 3:46 PM, Daniel Stutzbach
<[EMAIL PROTECTED]> wrote:
> On Jan 22, 2008 1:26 PM, tomer filiba <[EMAIL PROTECTED]> wrote:
> > >>> class Foo(object):
> > ... def __contains__(self, key):
> > ... return 17
> > ... def __eq__(self, other):
> > ... return 19
> > ...
> > >>>
> > >>> f=Foo()
> > >>> f == 8
> > 19
> > >>> 8 in f
> > True
>
> There are many places in the C implementation where a slot returns an
> int rather than a PyObject.  There other replies in this thread seem
> to support altering the signature of the slot to return a PyObject.
> Is this setting a precedent that _all_ slots should return a PyObject?
>
> Consider the following third behavior:
>
> >>> class foo(object):
> ... def __len__(self):
> ... return 'foo'
> ...
> >>> x = foo()
> >>> len(x)
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: an integer is required

Possibly. I guess it depends on the use case. It would be nice to
research this more, e.g. figure out how much code needs to be changed
to make each of these possible changes, and how likely there will be a
use case.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Daniel Stutzbach
On Jan 22, 2008 1:26 PM, tomer filiba <[EMAIL PROTECTED]> wrote:
> >>> class Foo(object):
> ... def __contains__(self, key):
> ... return 17
> ... def __eq__(self, other):
> ... return 19
> ...
> >>>
> >>> f=Foo()
> >>> f == 8
> 19
> >>> 8 in f
> True

There are many places in the C implementation where a slot returns an
int rather than a PyObject.  There other replies in this thread seem
to support altering the signature of the slot to return a PyObject.
Is this setting a precedent that _all_ slots should return a PyObject?

Consider the following third behavior:

>>> class foo(object):
... def __len__(self):
... return 'foo'
...
>>> x = foo()
>>> len(x)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: an integer is required

-- 
Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises LLC
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Guido van Rossum
The issue is that the sq_contains slot is defined as returning an int,
while the tp_richcompare slot is defined as returning a PyObject *.

Your first opportunity for changing this will be Py3k. Please submit a patch!

On Jan 22, 2008 11:26 AM, tomer filiba <[EMAIL PROTECTED]> wrote:
> i'm using python to create expression objects, for more intuitive
> usage as
> predicates, for instance:
> x = (Arg(0) > 17) & (Arg(1).foo == "bar")
> instead of
> x = And(Gt(Arg(0), 17), Eq(GetAttr(Arg(1), "foo"), "bar"))
>
> so now i can use x.eval(18, "spam") and get the result of the
> expression.
>
> i'm doing it by overriding all the operators to return expression
> objects,
> instead of evaluating the result immediately. it works fine, but i
> encountered
> a problem with making __contains__ behave so.
>
> it turns out __contains__ coerces the return value into a bool. this
> might
> seem logical at first, but is not consistent with the result of the
> language.
>
> consider the following code:
>
> >>> class Foo(object):
> ... def __contains__(self, key):
> ... return 17
> ... def __eq__(self, other):
> ... return 19
> ...
> >>>
> >>> f=Foo()
> >>> f == 8
> 19
> >>> 8 in f
> True
>
> as you can see, __eq__ does not coerces the result to bool, so why
> should
> __contains__ do that?
>
> i've looked at PySequence_Contains in objects/abstract.c, but i can't
> quite
> understand where the coercion is made. is because the function is
> typed
> as int? if so, i believe it should either be changed to PyObject, or
> have
> cmp_outcome (in ceval.c) not use this API directly, and rather return
> the
> result as it is returned from __contains__.
>
> i see no reason it should behave differently than __eq__ and the rest
> of comparison operators.
>
>
> -tomer
> ___
> Python-Dev mailing list
> Python-Dev@python.org
> http://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: 
> http://mail.python.org/mailman/options/python-dev/guido%40python.org
>



-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] misbehaving __contains__

2008-01-22 Thread Chuck Mason (Visual Concepts)
My guess is that results from the bottom of cmp_outcome (ceval.c),

The default case handles the PyCmp_EQ case via PyObject_RichCompare,
which might not return Py_True or Py_False.

But 'in' is handled inside the switch and is subject to the final
statements:

v = res ? Py_True : Py_False;
Py_INCREF(v);
return v

Though, IANAPydev. 

C

-Original Message-
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On
Behalf Of tomer filiba
Sent: Tuesday, January 22, 2008 11:27 AM
To: python-dev@python.org
Subject: [Python-Dev] misbehaving __contains__

i'm using python to create expression objects, for more intuitive
usage as
predicates, for instance:
x = (Arg(0) > 17) & (Arg(1).foo == "bar")
instead of
x = And(Gt(Arg(0), 17), Eq(GetAttr(Arg(1), "foo"), "bar"))

so now i can use x.eval(18, "spam") and get the result of the
expression.

i'm doing it by overriding all the operators to return expression
objects,
instead of evaluating the result immediately. it works fine, but i
encountered
a problem with making __contains__ behave so.

it turns out __contains__ coerces the return value into a bool. this
might
seem logical at first, but is not consistent with the result of the
language.

consider the following code:

>>> class Foo(object):
... def __contains__(self, key):
... return 17
... def __eq__(self, other):
... return 19
...
>>>
>>> f=Foo()
>>> f == 8
19
>>> 8 in f
True

as you can see, __eq__ does not coerces the result to bool, so why
should
__contains__ do that?

i've looked at PySequence_Contains in objects/abstract.c, but i can't
quite
understand where the coercion is made. is because the function is
typed
as int? if so, i believe it should either be changed to PyObject, or
have
cmp_outcome (in ceval.c) not use this API directly, and rather return
the
result as it is returned from __contains__.

i see no reason it should behave differently than __eq__ and the rest
of comparison operators.


-tomer
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
http://mail.python.org/mailman/options/python-dev/cmason%40vcentertainme
nt.com
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] misbehaving __contains__

2008-01-22 Thread tomer filiba
i'm using python to create expression objects, for more intuitive
usage as
predicates, for instance:
x = (Arg(0) > 17) & (Arg(1).foo == "bar")
instead of
x = And(Gt(Arg(0), 17), Eq(GetAttr(Arg(1), "foo"), "bar"))

so now i can use x.eval(18, "spam") and get the result of the
expression.

i'm doing it by overriding all the operators to return expression
objects,
instead of evaluating the result immediately. it works fine, but i
encountered
a problem with making __contains__ behave so.

it turns out __contains__ coerces the return value into a bool. this
might
seem logical at first, but is not consistent with the result of the
language.

consider the following code:

>>> class Foo(object):
... def __contains__(self, key):
... return 17
... def __eq__(self, other):
... return 19
...
>>>
>>> f=Foo()
>>> f == 8
19
>>> 8 in f
True

as you can see, __eq__ does not coerces the result to bool, so why
should
__contains__ do that?

i've looked at PySequence_Contains in objects/abstract.c, but i can't
quite
understand where the coercion is made. is because the function is
typed
as int? if so, i believe it should either be changed to PyObject, or
have
cmp_outcome (in ceval.c) not use this API directly, and rather return
the
result as it is returned from __contains__.

i see no reason it should behave differently than __eq__ and the rest
of comparison operators.


-tomer
___
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com