On Mon, May 30, 2011 at 5:28 PM, Henry Olders <henry.old...@mcgill.ca> wrote: > > 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: >> >> def main(): >> a = ['a list','with','three elements'] >> print a >> print fnc1(a) >> print a >> >> def fnc1(b): >> return fnc2(b) >> >> def fnc2(c): >> c[1] = 'having' >> 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 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. >> >> 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. >> >> 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 always 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 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). > > 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’s body, > it’s 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 ‘global’. > Though a bit surprising at first, a moment’s 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’d be using global all the time. You’d 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
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 > -- http://mail.python.org/mailman/listinfo/python-list