Re: My stupidity / strange inconsistency overriding class methods

2011-04-20 Thread andrew cooke
Thanks for finding that reference in the data model docs!  I was about to post 
a bug report because in PEP 3119 it says otherwise:

 The primary mechanism proposed here is to allow overloading the built-in 
 functions isinstance() and issubclass(). The overloading works as follows: 
 The call isinstance(x, C) first checks whether C.__instancecheck__ exists, 
 and if so, calls C.__instancecheck__(x) instead of its normal implementation. 

http://www.python.org/dev/peps/pep-3119/

But that's now what's implemented in Issue http://bugs.python.org/issue1708353 
which behaves as you quoted (only on the metaclass).

Cheers,
Andrew
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: My stupidity / strange inconsistency overriding class methods

2011-04-20 Thread andrew cooke
I didn't phrase that very well.  I do see the point about this being an 
instance lookup on a class...
-- 
http://mail.python.org/mailman/listinfo/python-list


My stupidity / strange inconsistency overriding class methods

2011-04-19 Thread andrew cooke
Hi,

I've been staring at this problem, in various forms, all day.  Am I missing 
something obvious, or is there some strange hardwiring of isinstance?  This is 
with Python 3.2.

class A(metaclass=ABCMeta):
@classmethod
def __instancecheck__(cls, instance): return False
# no override
assert isinstance(A(), A)
assert A.__class__.__instancecheck__(A, A())

class B(type):
def foo(self): return 42
class C(metaclass=B):
@classmethod
def foo(cls): return 7
# override
assert C().__class__.foo() == 7

It seems to me that the above two cases are inconsistent.  ABCMeta declares 
__instancecheck__ just like B declares foo.  Yet C can override foo, but A is 
unable to override the instance check.

Please help!

Thanks,
Andrew
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: My stupidity / strange inconsistency overriding class methods

2011-04-19 Thread andrew cooke
Also, there's something strange about the number of arguments (they're not 
consistent between the two examples - the A to __instancecheck__ should not 
be needed).  Yet it compiles and runs like that.  Very confused :o(
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: My stupidity / strange inconsistency overriding class methods

2011-04-19 Thread andrew cooke
OK, sorry, I see the mistake.  I'm confusing __class__ on the instance and on 
te class (the latter being the metaclass).  Sorry again, Andrew
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: My stupidity / strange inconsistency overriding class methods

2011-04-19 Thread Chris Rebert
On Tue, Apr 19, 2011 at 4:52 PM, andrew cooke and...@acooke.org wrote:
 Hi,

 I've been staring at this problem, in various forms, all day.  Am I missing 
 something obvious, or is there some strange hardwiring of isinstance?  This 
 is with Python 3.2.

        class A(metaclass=ABCMeta):
            @classmethod
            def __instancecheck__(cls, instance): return False
        # no override
        assert isinstance(A(), A)
        assert A.__class__.__instancecheck__(A, A())

[You've already figured out the issue, but since I spent a while
composing this, and for the benefit for the archives, I'll post
anyway.]

Makes sense after a little thought.
http://docs.python.org/reference/datamodel.html#customizing-instance-and-subclass-checks
Note that [ __instancecheck__() is ] looked up on the type
(metaclass) of a class. [It] cannot be defined as [a classmethod] in
the actual class. This is consistent with the lookup of special
methods that are called on instances, only in this case the instance
is itself a class.

Recall from 
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes
that lookup of __special__ methods never consults instance
dictionaries, instead skipping directly to the type's namespace; as
the quote says, in this case, the instance (of ABCMeta) is itself a
class/type (namely A). Your two assert statements are therefore almost
precisely equivalent in this case; and since the latter involves
A.__class__ (a.k.a. ABCMeta) rather than A itself, it's understandable
that that A's namespace is not consulted.

        class B(type):
            def foo(self): return 42
        class C(metaclass=B):
            @classmethod
            def foo(cls): return 7
        # override
        assert C().__class__.foo() == 7

More simply:  assert C.foo() == 7

foo is not a __special__ method name; therefore we look in the
instance dictionary of the receiver (i.e. C) before consulting the
receiver's type (i.e. B). Our check in the instance dictionary is
successful (we find C.foo), and therefore we don't even bother looking
at C's type (i.e. B, where we would find B.foo).

 It seems to me that the above two cases are inconsistent.  ABCMeta declares 
 __instancecheck__ just like B declares foo.  Yet C can override foo, but A is 
 unable to override the instance check.

The difference is in the __special__-ness of the method names in question.

Cheers,
Chris
--
http://blog.rebertia.com
-- 
http://mail.python.org/mailman/listinfo/python-list