Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!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; 'python,': 0.01; 'value,': 0.04; '(except': 0.05; 'parameter': 0.05; 'behave': 0.07; 'function,': 0.07; 'mode,': 0.07; 'references,': 0.07; 'snippet': 0.07; 'statements,': 0.07; 'subject:two': 0.07; 'python': 0.08; '(it': 0.09; 'accidentally': 0.09; 'assumed': 0.09; 'declarations': 0.09; 'object.': 0.09; 'parameter.': 0.09; 'prevents': 0.09; 'question:': 0.09; 'referenced': 0.09; 'respond.': 0.09; 'subject:parameters': 0.09; 'url:faq': 0.09; 'variables.': 0.09; 'pm,': 0.10; 'output': 0.11; 'def': 0.12; 'written': 0.14; 'debugging': 0.14; 'described': 0.14; 'wrote:': 0.14; 'defined': 0.14; '"free"': 0.16; '"global"': 0.16; '"private"': 0.16; '(ie': 0.16; "['a": 0.16; 'adopted': 0.16; 'arbitrarily': 0.16; 'bound)': 0.16; 'constructs': 0.16; 'declaration': 0.16; 'definition,': 0.16; 'definition;': 0.16; 'desirable,': 0.16; 'disciplined': 0.16; "function's": 0.16; 'function?': 0.16; 'globals.': 0.16; 'illustrates': 0.16; 'it",': 0.16; 'lexical': 0.16; 'lisp': 0.16; 'local.': 0.16; 'made-up': 0.16; 'main():': 0.16; 'namespace,': 0.16; 'narrow': 0.16; 'referenced,': 0.16; 'runtime.': 0.16; 'scope,': 0.16; 'scope.': 0.16; 'subject:function': 0.16; 'surprising': 0.16; 'ugly.': 0.16; 'url:html)': 0.16; 'workaround': 0.16; 'sections': 0.16; 'math': 0.16; 'mon,': 0.17; 'accessible': 0.19; 'compile': 0.19; 'happening': 0.19; 'programming': 0.19; 'header:In-Reply-To:1': 0.21; 'variable': 0.21; 'seems': 0.21; 'trying': 0.23; 'body.': 0.23; 'here?': 0.23; 'suggests': 0.23; 'url:wiki': 0.23; '(or': 0.24; 'code': 0.24; "doesn't": 0.25; '(and': 0.25; 'function': 0.25; 'changed': 0.25; 'modules': 0.26; 'parameters': 0.26; 'statement': 0.26; 'url:mailman': 0.26; 'object': 0.26; 'pass': 0.27; "i'm": 0.27; 'message-id:@mail.gmail.com': 0.28; '"the': 0.28; 'thanks': 0.28; 'changing': 0.28; 'helpful': 0.28; 'problem': 0.28; 'effect': 0.29; 'import': 0.29; 'bound': 0.29; 'explains': 0.29; 'explicitly': 0.29; 'functions.': 0.29; 'interact': 0.29; 'variables': 0.29; 'bit': 0.30; 'url:listinfo': 0.30; 'module': 0.30; '"in': 0.30; 'apologies.': 0.30; 'binding': 0.30; 'implicitly': 0.30; 'imported': 0.30; 'lot.': 0.30; 'modifying': 0.30; 'nested': 0.30; 'responded': 0.30; 'entry': 0.31; 'looks': 0.31; 'sort': 0.31; 'it.': 0.31; 'functional': 0.31; "didn't": 0.31; 'print': 0.31; 'this.': 0.31; 'done': 0.32; 'to:addr:python-list': 0.33; 'with.': 0.33; 'list': 0.33; 'list.': 0.33; 'making': 0.67; 'stated': 0.67; 'due': 0.67; 'address,': 0.71; 'encountered': 0.73; 'learned': 0.73; 'hand,': 0.74; '30,': 0.84; 'defeat': 0.84; 'deliberate': 0.84; 'visibility,': 0.84; 'dealt': 0.91; 'it\x92s': 0.91; 'local,': 0.91; 'distance.': 0.93 MIME-Version: 1.0 In-Reply-To: References: Date: Mon, 30 May 2011 17:52:27 -0700 Subject: Re: scope of function parameters (take two) From: Benjamin Kaplan To: python-list@python.org Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: quoted-printable X-Junkmail-Status: score=10/49, host=mpv1.tis.cwru.edu X-Junkmail-Signature-Raw: score=unknown, refid=str=0001.0A020202.4DE43BCD.00C1,ss=1,fgs=0, ip=74.125.82.182, so=2010-12-23 16:51:53, dmn=2009-09-10 00:05:08, mode=single engine X-Junkmail-IWF: false 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: 154 NNTP-Posting-Host: 82.94.164.166 X-Trace: 1306803220 news.xs4all.nl 49047 [::ffff:82.94.164.166]:39636 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:6684 On Mon, May 30, 2011 at 5:28 PM, Henry Olders wrot= e: > > On 2011-05-29, at 4:30 , Henry Olders wrote: > >> I just spent a considerable amount of time and effort debugging a progra= m. The made-up code snippet below illustrates the problem I encountered: >> >> def main(): >> =A0 =A0 =A0 a =3D ['a list','with','three elements'] >> =A0 =A0 =A0 print a >> =A0 =A0 =A0 print fnc1(a) >> =A0 =A0 =A0 print a >> >> def fnc1(b): >> =A0 =A0 =A0 return fnc2(b) >> >> def fnc2(c): >> =A0 =A0 =A0 c[1] =3D 'having' >> =A0 =A0 =A0 return c >> >> This is the output: >> ['a list', 'with', 'three elements'] >> ['a list', 'having', 'three elements'] >> ['a list', 'having', 'three elements'] >> >> I had expected the third print statement to give the same output as the = first, but variable a had been changed by changing variable c in fnc2. >> >> It seems that in Python, a variable inside a function is global unless i= t's assigned. This rule has apparently been adopted in order to reduce clut= ter by not having to have global declarations all over the place. >> >> I would have thought that a function parameter would automatically be co= nsidered local to the function. It doesn't make sense to me to pass a globa= l to a function as a parameter. >> >> One workaround is to call a function with a copy of the list, eg in fnc1= I would have the statement "return fnc2(b[:]". But this seems ugly. >> >> Are there others who feel as I do that a function parameter should alway= s be local to the function? Or am I missing something here? >> > > My thanks to all the people who responded - I've learned a lot. Sadly, I = feel that the main issue that I was trying to address, has not been dealt w= ith. Perhaps I didn't explain myself properly; if so, my apologies. > > I am trying to write python programs in a more-or-less functional program= ming mode, ie functions without side effects (except for print statements, = which are very helpful for debugging). This is easiest when all variables d= eclared in functions are local in scope (it would also be nice if variables= assigned within certain constructs such as for loops and list comprehensio= ns were local to that construct, but I can live without =A0it). > > It appears, from my reading of the python documentation, that a deliberat= e decision was made to have variables that are referenced but not assigned = in a function, have a global scope. I quote from the python FAQs: "In Pytho= n, variables that are only referenced inside a function are implicitly glob= al. If a variable is assigned a new value anywhere within the function=92s = body, it=92s assumed to be a local. If a variable is ever assigned a new va= lue inside the function, the variable is implicitly local, and you need to = explicitly declare it as =91global=92. > Though a bit surprising at first, a moment=92s consideration explains thi= s. On one hand, requiring global for assigned variables provides a bar agai= nst unintended side-effects. On the other hand, if global was required for = all global references, you=92d be using global all the time. You=92d have t= o declare as global every reference to a built-in function or to a componen= t of an imported module. This clutter would defeat the usefulness of the gl= obal declaration for identifying side-effects." (http://docs.python.org/faq= /programming.html) > > This suggests that the decision to make unassigned (ie "free" variables) = have a global scope, was made somewhat arbitrarily to =A0prevent clutter. B= ut I don't believe that the feared clutter would materialize. My understand= ing is that when a variable is referenced, python first looks for it in the= function's namespace, then the module's, and finally the built-ins. So why= would it be necessary to declare references to built-ins as globals? > > What I would like is that the variables which are included in the functio= n definition's parameter list, would be always treated as local to that fun= ction (and of course, accessible to nested functions) but NOT global unless= explicitly defined as global. This would prevent the sort of problems that= I encountered as described in my original post. I may be wrong here, but i= t seems that the interpreter/compiler should be able to deal with this, whe= ther the parameter passing is by value, by reference, by object reference, = or something else. If variables are not assigned (or bound) at compile time= , but are included in the parameter list, then the binding can be made at r= untime. > And I am NOT talking about variables that are only referenced in the body= of a function definition; I am talking about parameters (or arguments) in = the function's parameter list. As I stated before, there is no need to incl= ude a global variable in a parameter list, and if you want to have an effec= t outside of the function, that's what the return statement is for. > > I don't believe I'm the only person who thinks this way. Here is a quote = from wikipedia: "It is considered good programming practice to make the sco= pe of variables as narrow as feasible so that different parts of a program = do not accidentally interact with each other by modifying each other's vari= ables. Doing so also prevents action at a distance. Common techniques for d= oing so are to have different sections of a program use different namespace= s, or to make individual variables "private" through either dynamic variabl= e scoping or lexical variable scoping." (http://en.wikipedia.org/wiki/Varia= ble_(programming)#Scope_and_extent). > > It also seems that other languages suitable for functional programming ta= ke the approach I think python should use. Here is another quote from the w= ikipedia entry for Common Lisp: "the use of lexical scope isolates program = modules from unwanted interactions. Due to their restricted visibility, lex= ical variables are private. If one module A binds a lexical variable X, and= calls another module B, references to X in B will not accidentally resolve= to the X bound in A. B simply has no access to X. For situations in which = disciplined interactions through a variable are desirable, Common Lisp prov= ides special variables. Special variables allow for a module A to set up a = binding for a variable X which is visible to another module B, called from = A. Being able to do this is an advantage, and being able to prevent it from= happening is also an advantage; consequently, Common Lisp supports both le= xical and dynamic scope. (http://en.wikipedia.org/wiki/Common_Lisp#Determin= ers_of_scope). > > > If making python behave this way is impossible, then I will just have to = live with it. But if it's a question of "we've always done it this way", or= , " why change? I'm not bothered by it", then I will repeat my original que= stion: Are there others who feel as I do that a function parameter should a= lways be local to the function? > > And again, thank you all for taking the time to respond. > > Henry Python doesn't have true globals. When we say "global" what we mean is "module or built-in". Also, consider this code from math import sin def redundant_sin(x) : return sin(x) In Python, everything is an object. That includes functions. By your definition, that function would either have to be written as def redundant_sin(sin, x) : and you would have to pass the function in every time you wanted to call it or have a "global sin" declaration in your function. And you would need to do that for every single function that you call in your function body. > -- > http://mail.python.org/mailman/listinfo/python-list >