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
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: python-dev-bounces+cmason=vcentertainment.com@python.org [mailto:python-dev-bounces+cmason=vcentertainment.com@python.org] 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
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
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/)
On Jan 22, 2008 1:26 PM, tomer filiba
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 "<stdin>", line 1, in <module> TypeError: an integer is required
-- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises LLC
On Jan 22, 2008 3:46 PM, Daniel Stutzbach
On Jan 22, 2008 1:26 PM, tomer filiba
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 "<stdin>", line 1, in <module> 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/)
participants (4)
-
Chuck Mason (Visual Concepts)
-
Daniel Stutzbach
-
Guido van Rossum
-
tomer filiba