Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!news.dougwise.org!aioe.org!feeder.news-service.com!newsfeed.xs4all.nl!newsfeed6.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; 'attributes': 0.05; 'instance': 0.05; 'instance,': 0.05; 'char': 0.07; 'computed': 0.07; 'method,': 0.07; 'terry': 0.07; 'wrapper': 0.07; '>>>>': 0.09; 'attributes,': 0.09; 'bind': 0.09; 'bytes,': 0.09; 'callable.': 0.09; 'created,': 0.09; 'descriptor': 0.09; 'dict': 0.09; 'end,': 0.09; 'foo': 0.09; 'instance.': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:80.91.229.12': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'received:lo.gmane.org': 0.09; 'wrappers': 0.09; 'def': 0.13; 'am,': 0.14; 'wrote:': 0.14; 'attributes.': 0.16; 'believe.': 0.16; 'bytecode': 0.16; 'callable,': 0.16; 'creation,': 0.16; 'descriptors,': 0.16; 'eval': 0.16; 'indefinitely': 0.16; 'itself;': 0.16; 'methods,': 0.16; 'non- data': 0.16; 'properties.': 0.16; 'py3': 0.16; 'reedy': 0.16; 'richardson': 0.16; 'compiled': 0.18; 'bytes': 0.19; 'method.': 0.19; 'temporary': 0.19; 'appear': 0.19; 'jan': 0.22; 'header:In- Reply-To:1': 0.22; 'trying': 0.23; 'skip:{ 10': 0.23; 'objects': 0.24; 'memory': 0.24; 'calling': 0.25; 'version': 0.25; 'chris': 0.27; 'function': 0.27; 'string': 0.29; 'class': 0.29; 'bound': 0.29; 'implement': 0.30; 'objects.': 0.31; 'does': 0.31; 'it.': 0.31; 'anyone': 0.31; 'to:addr:python-list': 0.32; 'another': 0.32; '...': 0.32; 'words,': 0.33; 'created': 0.33; 'several': 0.33; 'sometimes': 0.33; 'header:X-Complaints-To:1': 0.34; 'requires': 0.35; 'there': 0.35; 'normally': 0.35; 'problem,': 0.35; 'print': 0.35; 'header:User-Agent:1': 0.35; 'accessing': 0.35; 'instances': 0.35; 'too': 0.36; 'else': 0.37; 'data': 0.37; 'some': 0.37; 'strings': 0.38; 'but': 0.38; 'happens': 0.38; 'received:org': 0.38; 'anything': 0.38; 'unless': 0.38; 'ok,': 0.39; 'to:addr:python.org': 0.39; 'subject: (': 0.39; 'header :Mime-Version:1': 0.39; 'how': 0.39; 'finished': 0.40; 'would': 0.40; 'header:Received:5': 0.40; 'details': 0.64; 'ever': 0.65; 'enable': 0.65; 'cause': 0.65; 'subject:The': 0.69; '100': 0.70; 'kept': 0.73; 'million': 0.75; '__call__': 0.84; 'common,': 0.84; 'concatenate': 0.84; 'have?': 0.84; 'mil': 0.91 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: The Magick of __call__ (Or, Digging Deeper Than I Ought To) Date: Fri, 01 Apr 2011 17:35:18 -0400 References: <4D95EA23.10802@aim.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: rain.gmane.org User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.15) Gecko/20110303 Lightning/1.0b2 Thunderbird/3.1.9 In-Reply-To: <4D95EA23.10802@aim.com> 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: 71 NNTP-Posting-Host: 82.94.164.166 X-Trace: 1301693729 news.xs4all.nl 81474 [::ffff:82.94.164.166]:33986 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:2409 On 4/1/2011 11:07 AM, Corey Richardson wrote: > All callables (things you can foo(bar)) are really just objects that > implement the __call__ method, as far as I understand. > Well then, that would appear to make methods themselves callable, Method are just function objects that are class attributes. They are sometimes wrapped as method objects. Details are different between Py2 and Py3. >>>> class Foo(object): > ... def __call__(self, foo): > ... self.name(foo) A __call__ instance method makes instances of the class callable. > ... def name(self, bar): > ... print "Name: {0}".format(bar) > ... >>>> foo = Foo() >>>> foo("Me!") > Name: Me! > > Ok, nothing out of the ordinary. But what happens if.... > >>>> foo.name.__call__("Corey") > Name: Corey >>>> eval("foo.name" + (".__call__" * 9001) + "('Corey')") > Name: Corey >>>> foo.name.__call__.__call__.__call__.__call__.__call__("Corey") > Name: Corey >>>> eval("foo.name" + (".__call__" * 100000000) + "('Corey')") Yes, trying to create a string of 900 million chars may cause a problem, especially when you try to concatenate anything on the end, which requires another 900 million char string to be created before the temporary is freed. How much memory do you have? To find out if the strings creation, or compilation, every finished s = "foo.name" + (".__call__" * 100000000) + "('Corey')" print 's done' c = compile(s,'test','eval') print 'c done' eval(s) If s is created, the compiled bytecode will be 200 mil bytes, I believe. If eval ever starts, it will first create 100 million wrappers, as Chris showed, before calling the last. Each is 32 bytes in Py3.2. > looked!). Would looking at something such as PyPy's version of it be > good for me / does anyone else have insights? As to why method wrappers are not reused (explaining in Py3 terms): accessing a method through the class returns the function/method itself; accessing a method through an instance returns some type of bound method wrapper. There are several types of wrapper for the various types of callablesdef , but each has attributes that enable access to both the method and instance. The __call__ method for a particular type of wrapper knows how to call instances of that type of bound method. In other words, method attributes of instances are computed attributes, much like data properties. Functions are non-data descriptors, as explained in the descriptor HOW-TO. Every time a method is accessed through an instance, a new wrapper is created. Why? 1. If you want to reuse a bound methods, just bind it to a name or something and reuse it. 2. To automatically keep it for possible reuse, which normally is not too common, it wold have to be kept in some hidden dict which would grow indefinitely unless pruned occasionally. -- Terry Jan Reedy