Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!news.albasani.net!feeder.erje.net!newsfeed.xs4all.nl!newsfeed5.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'instance': 0.05; '(of': 0.07; 'check.': 0.07; 'dictionary': 0.07; 'forms,': 0.07; 'involves': 0.07; 'skipping': 0.07; 'python': 0.07; 'assert': 0.09; 'namespace': 0.09; 'override': 0.09; 'says,': 0.09; 'looked': 0.10; 'pm,': 0.11; 'received:74.125.82.174': 0.12; 'received:mail-wy0-f174.google.com': 0.12; 'wrote:': 0.14; 'defined': 0.15; '3.2.': 0.16; 'declares': 0.16; 'foo,': 0.16; 'foo.': 0.16; 'instances,': 0.16; 'lookup': 0.16; 'namespace;': 0.16; 'thought.': 0.16; "type's": 0.16; '(i.e.': 0.18; 'question.': 0.18; 'url:blog': 0.18; 'bother': 0.19; 'tue,': 0.20; 'cc:no real name:2**0': 0.20; 'cc:2**0': 0.20; 'cheers,': 0.20; 'seems': 0.21; 'header:In-Reply-To:1': 0.22; 'cc:addr:python- list': 0.22; 'issue,': 0.23; 'itself,': 0.23; '(we': 0.24; 'skip:_ 20': 0.24; 'cases': 0.25; 'equivalent': 0.26; "i'll": 0.26; 'instead': 0.26; 'unable': 0.26; 'chris': 0.27; 'message- id:@mail.gmail.com': 0.28; 'hi,': 0.29; 'class.': 0.29; 'cc:addr:python.org': 0.31; 'name;': 0.31; 'recall': 0.31; 'actual': 0.31; 'called': 0.32; "i've": 0.33; 'url:docs': 0.33; 'post': 0.34; 'difference': 0.35; 'there': 0.35; 'problem,': 0.35; 'latter': 0.35; 'rather': 0.36; 'missing': 0.36; 'case,': 0.36; 'two': 0.37; 'some': 0.37; 'case': 0.37; 'url:python': 0.37; 'andrew': 0.38; 'apr': 0.38; 'consistent': 0.38; 'received:google.com': 0.38; 'but': 0.38; 'url:org': 0.38; 'where': 0.39; 'would': 0.40; "it's": 0.40; 'header:Received:5': 0.40; '8bit%:14': 0.60; '2011': 0.62; 'our': 0.63; 'strange': 0.65; 'special': 0.66; 'benefit': 0.66; 'day.': 0.71; 'skip:\xc2 10': 0.83; '"foo"': 0.84; 'case;': 0.84; 'staring': 0.84; 'subject:class': 0.84; 'obvious,': 0.91; 'to:none': 0.92; 'receiver': 0.93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rebertia.com; s=google; h=domainkey-signature:mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:cc:content-type :content-transfer-encoding; bh=sXxZKYatLItcOXx/pK5nZjwcpFDcQcISDp73Web3ADc=; b=WOPnsfk6xrx8sgiNTETslmTkArzPXQGnxgICjdqowyifiyis7c42AJVIBPw2n0n1JA bdkilC11kZBGWr5mdnW5k5+fOk83BGYczum6G4VQnFpWzCMZuitcD09nsEQk9liQVats 6+O/KQdKRd6h3UdC9tJtXijTk6E4ayOvuIy2E= DomainKey-Signature: a=rsa-sha1; c=nofws; d=rebertia.com; s=google; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:cc:content-type :content-transfer-encoding; b=dz16gIb8jr6qIPpSjIEdFZlOOzvLL9dEeIwa9uAxOlxlsyVOdM6AGdpnhSaZISE2i8 knGJ7jBU57T6n6TEIfgDKg8ysOaW3m3eHmf9MWAkwr6btIO8uhZmLS/0MYa5AHmpFaZY rpNUO/7SqeHs5b04+fRECHSGfa7qstM2cyWBw= MIME-Version: 1.0 Sender: chris@rebertia.com In-Reply-To: <31d5393f-9c16-4188-ae30-b36f1d2156ba@glegroupsg2000goo.googlegroups.com> References: <31d5393f-9c16-4188-ae30-b36f1d2156ba@glegroupsg2000goo.googlegroups.com> Date: Tue, 19 Apr 2011 17:45:42 -0700 X-Google-Sender-Auth: 6eMI3vlz2GErBKlKh9rRdbb8vuM Subject: Re: My stupidity / strange inconsistency overriding class methods From: Chris Rebert Cc: python-list@python.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 64 NNTP-Posting-Host: 82.94.164.166 X-Trace: 1303260344 news.xs4all.nl 65870 [::ffff:82.94.164.166]:56294 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:3620 On Tue, Apr 19, 2011 at 4:52 PM, andrew cooke wrote: > Hi, > > I've been staring at this problem, in various forms, all day. =C2=A0Am I = missing something obvious, or is there some strange hardwiring of isinstanc= e? =C2=A0This is with Python 3.2. > > =C2=A0 =C2=A0 =C2=A0 =C2=A0class A(metaclass=3DABCMeta): > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0@classmethod > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0def __instancecheck__(cls, insta= nce): return False > =C2=A0 =C2=A0 =C2=A0 =C2=A0# no override > =C2=A0 =C2=A0 =C2=A0 =C2=A0assert isinstance(A(), A) > =C2=A0 =C2=A0 =C2=A0 =C2=A0assert 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-su= bclass-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. > =C2=A0 =C2=A0 =C2=A0 =C2=A0class B(type): > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0def foo(self): return 42 > =C2=A0 =C2=A0 =C2=A0 =C2=A0class C(metaclass=3DB): > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0@classmethod > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0def foo(cls): return 7 > =C2=A0 =C2=A0 =C2=A0 =C2=A0# override > =C2=A0 =C2=A0 =C2=A0 =C2=A0assert C().__class__.foo() =3D=3D 7 More simply: assert C.foo() =3D=3D 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. =C2=A0ABCMeta d= eclares __instancecheck__ just like B declares foo. =C2=A0Yet C can overrid= e 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