Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!selfless.tophat.at!newsfeed.xs4all.nl!newsfeed6.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.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; 'header:In-reply-to:1': 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; 'output': 0.11; 'def': 0.12; 'debugging': 0.14; 'described': 0.14; 'wrote:': 0.14; 'defined': 0.14; '"free"': 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; 'desirable,': 0.16; 'disciplined': 0.16; "function's": 0.16; 'function?': 0.16; 'illustrates': 0.16; 'it",': 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; 'accessible': 0.19; 'compile': 0.19; 'happening': 0.19; 'programming': 0.19; 'variable': 0.21; 'seems': 0.21; 'trying': 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; 'object': 0.26; 'pass': 0.27; "i'm": 0.27; '"the': 0.28; 'thanks': 0.28; 'changing': 0.28; 'helpful': 0.28; 'problem': 0.28; 'effect': 0.29; 'bound': 0.29; 'explains': 0.29; 'explicitly': 0.29; 'interact': 0.29; 'variables': 0.29; 'bit': 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; "i've": 0.33; 'question': 0.34; 'rule': 0.34; 'thank': 0.35; 'there': 0.35; 'body,': 0.35; 'function.': 0.35; 'module.': 0.35; 'visible': 0.35; 'languages': 0.35; 'believe': 0.66; 'here': 0.66; 'special': 0.66; 'making': 0.67; 'stated': 0.67; 'due': 0.67; 'address,': 0.71; 'encountered': 0.73; 'learned': 0.73; 'hand,': 0.74; 'defeat': 0.84; 'deliberate': 0.84; 'received:videotron.ca': 0.84; 'visibility,': 0.84; 'dealt': 0.91; 'it\x92s': 0.91; 'local,': 0.91; 'distance.': 0.93 MIME-version: 1.0 Content-type: text/plain; charset=windows-1252 Subject: Re: scope of function parameters (take two) From: Henry Olders In-reply-to: Date: Mon, 30 May 2011 20:28:34 -0400 Content-transfer-encoding: quoted-printable References: To: python-list@python.org X-Mailer: Apple Mail (2.1084) 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: 138 NNTP-Posting-Host: 82.94.164.166 X-Trace: 1306801730 news.xs4all.nl 49182 [::ffff:82.94.164.166]:46523 X-Complaints-To: abuse@xs4all.nl Xref: x330-a1.tempe.blueboxinc.net comp.lang.python:6679 On 2011-05-29, at 4:30 , Henry Olders wrote: > I just spent a considerable amount of time and effort debugging a = program. The made-up code snippet below illustrates the problem I = encountered: >=20 > def main(): > a =3D ['a list','with','three elements'] > print a > print fnc1(a) > print a > =09 > def fnc1(b): > return fnc2(b) >=20 > def fnc2(c): > c[1] =3D 'having' > return c >=20 > This is the output: > ['a list', 'with', 'three elements'] > ['a list', 'having', 'three elements'] > ['a list', 'having', 'three elements'] >=20 > 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. >=20 > It seems that in Python, a variable inside a function is global unless = it's assigned. This rule has apparently been adopted in order to reduce = clutter by not having to have global declarations all over the place. >=20 > I would have thought that a function parameter would automatically be = considered local to the function. It doesn't make sense to me to pass a = global to a function as a parameter. >=20 > 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. >=20 > Are there others who feel as I do that a function parameter should = always be local to the function? Or am I missing something here? >=20 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 with. Perhaps I didn't explain myself properly; if so, my = apologies. I am trying to write python programs in a more-or-less functional = programming mode, ie functions without side effects (except for print = statements, which are very helpful for debugging). This is easiest when = all variables declared in functions are local in scope (it would also be = nice if variables assigned within certain constructs such as for loops = and list comprehensions were local to that construct, but I can live = without it).=20 It appears, from my reading of the python documentation, that a = deliberate 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 Python, variables that are only referenced inside a function = are implicitly global. 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 value 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 = this. On one hand, requiring global for assigned variables provides a = bar against 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 to declare as global every reference to a built-in = function or to a component of an imported module. This clutter would = defeat the usefulness of the global 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 prevent clutter. = But I don't believe that the feared clutter would materialize. My = understanding 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 = function definition's parameter list, would be always treated as local = to that function (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 it seems that the interpreter/compiler should be able = to deal with this, whether 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 runtime. 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 include a global variable in a parameter list, and if you = want to have an effect 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 = scope 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 variables. Doing so also prevents action at a distance. Common = techniques for doing so are to have different sections of a program use = different namespaces, or to make individual variables "private" through = either dynamic variable scoping or lexical variable scoping." = (http://en.wikipedia.org/wiki/Variable_(programming)#Scope_and_extent). It also seems that other languages suitable for functional programming = take the approach I think python should use. Here is another quote from = the wikipedia entry for Common Lisp: "the use of lexical scope isolates = program modules from unwanted interactions. Due to their restricted = visibility, lexical 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 provides 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 lexical and = dynamic scope. = (http://en.wikipedia.org/wiki/Common_Lisp#Determiners_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 question: Are there others who feel as I do that a function = parameter should always be local to the function? And again, thank you all for taking the time to respond. Henry