Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.mixmin.net!feeder.erje.net!eu.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; 'python,': 0.02; 'attribute': 0.05; 'case.': 0.05; 'context': 0.05; 'method.': 0.05; 'class,': 0.07; 'computed': 0.07; 'matches': 0.07; 'method,': 0.07; 'suppose': 0.07; "'\\n')": 0.09; '@property': 0.09; 'expected.': 0.09; 'instance.': 0.09; 'itself,': 0.09; 'literal': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'sep': 0.09; 'substitution': 0.09; 'terry': 0.09; 'wrong,': 0.09; 'def': 0.10; 'resulting': 0.13; 'ignore': 0.13; 'cases': 0.15; 'properly': 0.15; 'result.': 0.15; '0):': 0.16; 'computes': 0.16; 'evaluating': 0.16; 'expected,': 0.16; 'foo()': 0.16; 'posted.': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'self)': 0.16; 'self.x,': 0.16; 'substitute': 0.16; 'wrote:': 0.17; 'example.': 0.17; 'instance': 0.17; 'instance,': 0.17; 'thu,': 0.17; 'typical': 0.17; 'typing': 0.17; 'written,': 0.17; 'examples': 0.18; 'jan': 0.18; '>>>': 0.18; 'written': 0.20; 'import': 0.21; 'assuming': 0.22; 'closely': 0.22; 'class.': 0.23; 'ignored.': 0.23; 'least': 0.25; 'header:In- Reply-To:1': 0.25; 'header:User-Agent:1': 0.26; '---': 0.26; 'am,': 0.27; 'besides': 0.27; 'interface': 0.27; 'header:X -Complaints-To:1': 0.28; 'actual': 0.28; 'arguments.': 0.29; 'context,': 0.29; "d'aprano": 0.29; 'steven': 0.29; 'case,': 0.29; 'skip:_ 10': 0.29; 'class': 0.29; 'classes': 0.30; "skip:' 10": 0.30; 'normally': 0.30; 'sense': 0.31; 'code': 0.31; 'point': 0.31; 'cases,': 0.33; 'int': 0.33; 'interface,': 0.33; 'problem': 0.33; 'to:addr:python-list': 0.33; 'point.': 0.33; 'another': 0.33; 'agree': 0.34; 'nov': 0.35; 'expected': 0.35; 'pm,': 0.35; 'received:org': 0.36; 'but': 0.36; 'method': 0.36; 'should': 0.36; 'too': 0.36; 'possible': 0.37; 'does': 0.37; 'subject:: ': 0.38; 'object': 0.38; 'some': 0.38; 'to:addr:python.org': 0.39; 'takes': 0.39; 'where': 0.40; 'header:Received:5': 0.40; 'your': 0.60; 'matter': 0.61; 'situation': 0.62; 'details': 0.63; 'customized': 0.64; 'here': 0.65; 'gave': 0.65; 'differences': 0.65; 'matter.': 0.65; 'subjectcharset:utf-8': 0.72; 'received:fios.verizon.net': 0.84 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: duck typing =?UTF-8?B?YXNzZXJ04oCP?= Date: Fri, 09 Nov 2012 12:03:11 -0500 References: <509c42e3$0$29980$c3e8da3$5496439d@news.astraweb.com> <509ca300$0$29980$c3e8da3$5496439d@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: pool-173-75-251-66.phlapa.fios.verizon.net User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120824 Thunderbird/15.0 In-Reply-To: <509ca300$0$29980$c3e8da3$5496439d@news.astraweb.com> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 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: 114 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1352480612 news.xs4all.nl 6879 [2001:888:2000:d::a6]:40147 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:33035 On 11/9/2012 1:30 AM, Steven D'Aprano wrote: > On Thu, 08 Nov 2012 23:44:54 -0500, Terry Reedy wrote: > >> On 11/8/2012 6:40 PM, Steven D'Aprano wrote: > [...] >>> IFoo.bar # returns a computed property >> >> Assuming IFoo is a class and bar is a property attribute of the class, >> IFoo.bar is the property object itself, not the computed property of an >> instance. > > Given the context we were discussing, namely duck-typing, the examples I > gave should have been understood as indications, not literal code > snippets. For the situation we are discussing, details matter. 'Indications' are not sufficient. > But in context, duck-typing classes normally is intended to substitute an > instance of one class for an instance of another class. This we agree on. > In that case, if > IFoo.bar is a property, and Foo.bar is a method, then you cannot > substitute an IFoo instance for a Foo instance, or vice versa: If the property is properly written, this is wrong, as I showed in the working code you snipped and apparently ignored. Or at least you have not shown a problem with the code I posted. > ifoo = IFoo() > ifoo.bar # returns a computed attribute If the computed attribute is a method, ifoo.bar() # calls the method > foo = Foo() > foo.bar() # calls the method > In the general case, you cannot use ifoo.bar() where foo.bar() is > expected, nor can you use foo.bar where ifoo.bar is expected. In my actual code example, one can make the substitution in typical usage. 'In general', no substitution will work in all possible use cases, with unlimited introspection. But that is besides the point. The point of duck typing is to worry about the details that matter and ignore the differences that do not matter. What matters in a specific case depend on the case. In many cases in Python, using isinstance, for instance, is looking too closely at details that do not matter. But in some cases, the actual class does matter and then we do use isinstance. > Suppose the expected interface is that instance.bar is a method that > takes no arguments. This is exactly the situation for my code example. Here it is again: --- from types import MethodType as bm class C: def __init__(self, x = 0): self.x = x def double(self): return 2 * self.x class Cp: def __init__(self, x = 0): self.x = x @property def double(self): return bm(lambda self: 2 * self.x, self) c, cp = C(3), Cp(3) print(c.double, cp.double, c.double(), cp.double(), sep = '\n') --- >>> > of <__main__.Cp object at 0x0000000003185A58>> 6 6 --- If the interface requires isinstance(inst.double.__self__, C) # or inst.double.__func__.__name__ == 'double' then cp is not a substitute for c. But we would normally consider that an over-specified interface. > foo.bar() matches that interface, because bar is a > method. But ifoo.bar is a property. Not in the sense that matters here. It is the result of calling the .get method of the Ifoo.bar property. If that result is a bound instance method, just as with foo.bar, then what is your problem with it, for the interface specified? > Suppose it computes an int result. If the object resulting from evaluating ifoo.bar does not match the expected interface, IT DOES NOT MATTER whether the object is the result of normal attribute access or of customized access via either __getattr__ or a property. Anyway, I am supposing that Ifoo is written properly to match the expected interface. Here, that means that the property computes a bound method. -- Terry Jan Reedy