Path: csiph.com!usenet.pasdenom.info!news.etla.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed3.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!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.007 X-Spam-Evidence: '*H*': 0.99; '*S*': 0.00; 'attribute': 0.07; 'mouse': 0.07; 'preservation': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'def': 0.12; 'jan': 0.12; 'wrote': 0.14; ':-(': 0.16; 'closure.': 0.16; 'closures': 0.16; "function's": 0.16; 'of)': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'reedy': 0.16; 'sense,': 0.16; 'slip': 0.16; 'wrote:': 0.18; 'module': 0.19; 'replacing': 0.19; 'user.': 0.19; '>>>': 0.22; 'input': 0.22; 'import': 0.22; 'header :User-Agent:1': 0.23; 'decorators': 0.24; 'module,': 0.24; 'text,': 0.24; '(or': 0.24; 'environment': 0.24; 'right.': 0.26; 'header:X-Complaints-To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'testing': 0.29; 'have,': 0.30; 'easier': 0.31; "d'aprano": 0.31; 'second,': 0.31; 'steven': 0.31; 'testing.': 0.31; 'writes:': 0.31; 'maintaining': 0.32; 'another': 0.32; 'becomes': 0.33; 'fri,': 0.33; 'display': 0.35; 'definition': 0.35; 'late': 0.35; 'but': 0.35; 'idle': 0.36; 'in.': 0.36; 'opposed': 0.36; 'thanks': 0.36; 'subject:?': 0.36; 'wrong': 0.37; 'two': 0.37; 'to:addr:python-list': 0.38; 'pm,': 0.38; 'that,': 0.38; 'environment.': 0.39; 'skip:. 10': 0.39; 'to:addr:python.org': 0.39; 'skip:p 20': 0.39; 'received:org': 0.40; 'called': 0.40; 'new': 0.61; 'balance': 0.61; 'received:173': 0.61; 'course': 0.61; 'different': 0.65; 'relatively': 0.65; 'brain': 0.68; 'surrounding': 0.68; '100': 0.79; '(probably': 0.84; '*really*': 0.84; 'received:fios.verizon.net': 0.84; 'snapshot': 0.84; 'from.': 0.93; '2013': 0.98 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Reedy Subject: Re: closure = decorator? Date: Fri, 11 Oct 2013 16:51:15 -0400 References: <707e67a6-c398-4d0a-a058-76b8bf2829f0@googlegroups.com> <5257c3dd$0$29984$c3e8da3$5496439d@news.astraweb.com> <52582b08$0$29984$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:24.0) Gecko/20100101 Thunderbird/24.0 In-Reply-To: <52582b08$0$29984$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: 73 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1381524692 news.xs4all.nl 15968 [2001:888:2000:d::a6]:34183 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:56710 On 10/11/2013 12:44 PM, Steven D'Aprano wrote: > On Fri, 11 Oct 2013 15:01:40 +0300, Jussi Piitulainen wrote: > >> Steven D'Aprano writes: >>> Closures have nothing to do with *arguments*. A better definition of a >>> closure is that it is a function together with a snapshot of the >>> environment it was called from. > [...] >> Second, it's precisely not (a snapshot of) the environment where the >> function is *called* from, it's (a snapshot of) the environment where >> the function was *created* in. This is the whole *point*. > > Ah yes, of course you are right. I actually knew that, it was a slip of > the brain that I wrote it wrong :-( > > Thanks for the correction. The closure is also not a 'snapshot' but a reference to (or preservation of) (relevant parts of) the environment. A snapshot of the environment at the time of definition would have been much easier to implement. x = 1 def outer(): y = 1 def inner(): return x + y y = 2 return inner x = 2 print(outer()()) # 4 In a sense, all user functions are closures in that they have, and have always had, a reference to their definition module environment -- the readonly .__globals__ attribute (probably .func_globals in 2.x). This lexical, as opposed to dynamic scoping, becomes noticable when one import a function from another module, as for testing. Because .__globals__ is read-only, one must monkey-patch the module of definition to change the function's global (modular) environment, as when replacing an object it uses with a mock. I ran into this when testing Idle methods that use a tk message box to display a message and wait for input (sometimes text, always a mouse click) from a human user. What is relatively new (and tricky) is capturing local names of surrounding functions while maintaining both late binding and independent writability for each closure. This last means that the following works: def account(): balance = 0 def trans(amt): nonlocal balance balance += amt return balance return trans xmasfund = account() pettycash = account() print(xmasfund(100)) # 100 print(pettycash(50)) # 50 print(xmasfund(-100)) # 0 print(pettycash(-25)) # 25 Closures and decorators are *really* two different subjects. -- Terry Jan Reedy