Re: scope of function parameters (take two)
On 2011-05-31, at 1:13 , Wolfgang Rohdewald wrote: what you really seem to want is that a function by default cannot have any side effects (you have a side effect if a function changes things outside of its local scope). But that would be a very different language than python You're partially right - what I want is a function that is free of side effects back through the parameters passed in the function call. Side effects via globals or print statements is fine by me. python seems to be undergoing changes all the time. List comprehensions were added in python 2.0, according to wikipedia. I like list comprehensions and use them all the time because they are powerful and concise. did you read the link Steven gave you? http://mail.python.org/pipermail/tutor/2010-December/080505.html Yes, I did, thanks. Henry -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Mon, May 30, 2011 at 11:37 PM, Henry Olders henry.old...@mcgill.ca wrote: On 2011-05-31, at 1:13 , Wolfgang Rohdewald wrote: what you really seem to want is that a function by default cannot have any side effects (you have a side effect if a function changes things outside of its local scope). But that would be a very different language than python You're partially right - what I want is a function that is free of side effects back through the parameters passed in the function call. Side effects via globals or print statements is fine by me. So, you have no problem with *global* side effects, but side effects with a /more constrained/ scope bother you? That's kinda odd, IMO. Cheers, Chris -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On 2011-05-30, at 20:52 , Benjamin Kaplan wrote: 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: 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. I don't believe so. Within redundant_sin, x is local, so if I change x, it will not change any objects named x outside of the function. As far as sin is concerned, if it were passed to redundant_sin via the parameter list, then it would be local, but otherwise sin would be looked for in the function definition; if not found there, it would be looked for in the module, where it would be found. I am not suggesting any changes to how names are looked up or scoped. Henry -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On 2011-05-31, at 24:35 , Dan Stromberg wrote: On Mon, May 30, 2011 at 5:28 PM, Henry Olders henry.old...@mcgill.ca wrote: Be careful not to conflate global scoping or global lifetime, with mutability or pure, side-effect-free functions (callables). It sounds like what you want is immutability and/or freedom from side effects, which is found most often in (pure) functional languages - which is not what Python is, nor does it attempt to be so. I think you're right, I've been conflating scoping with side effects caused by passing mutable objects. In Python, and in many other languages, if you pass a scalar (or more generally, an object of an immutable type) to a function, and then change the scalar in that function, you only change the scalar within that function, not within the caller. However, if you pass an aggregate type like a list (array) or dictionary (hash table), then the formal argument itself that you've passed is still only changeable within that function, however what it points off at _is_ changeable via that formal argument. This is of course because otherwise passing a 1 gigabyte dictionary to a function would either have to copy the whole dictionary, or implement some sort of Copy-on-Write semantics, or make it somehow readonly. If you need side effect-free functions in Python, you'd probably best copy your aggregates, EG: import copy def main(): a = ['a list','with','three elements'] print a print fnc1(a) print a def fnc1(b): b = copy.deepcopy(b) return fnc2(b) def fnc2(c): c = copy.deepcopy(c) c[1] = 'having' return c Clearly, making a copy within the function eliminates the possibility of the side effects caused by passing in mutable objects. Would having the compiler/interpreter do this automatically make python so much different? What if it were optional, like nested scopes were in python 2.1 until they became standard in 2.2? Henry -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 6:17 PM, Henry Olders henry.old...@mcgill.ca wrote: Clearly, making a copy within the function eliminates the possibility of the side effects caused by passing in mutable objects. Would having the compiler/interpreter do this automatically make python so much different? As I've pointed, you can make decorator to do that. Adding @copy_args to each function you intend to be pure is not that hard. import decorator import copy @decorator.decorator def copy_args(f, *args, **kw): nargs = [] for arg in args: nargs.append(copy.deepcopy(arg)) nkw = {} for k,v in kw.iteritems(): nkw[k] = copy.deepcopy(v) return f(*nargs, **nkw) @copy_args def test(a): a.append(1) return a l = [0] test(l) [0, 1] l [0] inspect.getargspec(test) ArgSpec(args=['a'], varargs=None, keywords=None, defaults=None) So this decorator achieves needed result and preserves function signatures. -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 5:17 PM, Henry Olders henry.old...@mcgill.ca wrote: Clearly, making a copy within the function eliminates the possibility of the side effects caused by passing in mutable objects. Would having the compiler/interpreter do this automatically make python so much different? Yes, it would make Python quite different. If suddenly you couldn't pass a mutable object to a function to get it muted (that sounds wrong), then code will break. Also, there's a fairly serious performance penalty to copying everything when it's not necessary. As has been suggested, you can specifically and deliberately cause this effect for any function(s) you wish to protect in this way; there's no need to change the language's fundamentals to do it. Chris Angelico -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Dienstag 31 Mai 2011, Henry Olders wrote: You're partially right - what I want is a function that is free of side effects back through the parameters passed in the function call. I don't know any object oriented language where it is not possible to change objects passed in as parameters. It is up to the passed object (a list in your case) to allow or disallow manipulations no matter how they are invocated, and the object is the same in the calling code and in the called function. -- Wolfgang -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On 5/31/2011 2:37 AM, Henry Olders wrote: what I want is a function that is free of side effects back through the parameters passed in the function call. You can get that by refraining from mutating parameter objects. Simple as that. Just do not expect Python to enforce that discipline on everyone else. To be really functional, and never mutate objects, do not use Python lists, which are arrays. Use linked-list trees, like Lisp languages and perhaps others do. One can easily do this with tuples, or a subclass of tuples, or a class wrapping tuples. Linked-lists and functional programming go together because prepending to a linked list creates a new object while appending to a Python list mutates an existing list. Similarly, popping from a linked list retrieves an item and an existing sublist while popping from a Python list retrieves and item and mutates the list. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On 5/31/2011 3:17 AM, Henry Olders wrote: Clearly, making a copy within the function eliminates the possibility of the side effects caused by passing in mutable objects. Mutable objects and mutating methods and functions are a *feature* of Python. If you do not like them, do not use them. Would having the compiler/interpreter do this automatically make python so much different? Yes. How would you then write a function like list.sort or list.pop? It is fundamental that parameters are simply local names that must be bound as part of the calling process. After that, they are nothing special. Python is a language for adults that take responsibility for what they do. If you do not like argument-mutating functions, then do not write them and do not use them (without making a copy yourself). Python was not designed to model timeless immutable mathematics. It is an information-object manipulation language and in real life, we mutate collections and associations all the time. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 1:38 AM, Daniel Kluev dan.kl...@gmail.com wrote: @decorator.decorator def copy_args(f, *args, **kw): nargs = [] for arg in args: nargs.append(copy.deepcopy(arg)) nkw = {} for k,v in kw.iteritems(): nkw[k] = copy.deepcopy(v) return f(*nargs, **nkw) There is no decorator module in the standard library. This must be some third-party module. The usual way to do this would be: def copy_args(f): @functools.wraps(f) def wrapper(*args, **kw): nargs = map(copy.deepcopy, args) nkw = dict(zip(kw.keys(), map(copy.deepcopy, kw.values( return f(*nargs, **nkw) return wrapper Note that this will always work, whereas the decorator.decorator version will break if the decorated function happens to take a keyword argument named f. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 9:16 AM, Ian Kelly ian.g.ke...@gmail.com wrote: On Tue, May 31, 2011 at 1:38 AM, Daniel Kluev dan.kl...@gmail.com wrote: @decorator.decorator def copy_args(f, *args, **kw): nargs = [] for arg in args: nargs.append(copy.deepcopy(arg)) nkw = {} for k,v in kw.iteritems(): nkw[k] = copy.deepcopy(v) return f(*nargs, **nkw) There is no decorator module in the standard library. This must be some third-party module. The usual way to do this would be: def copy_args(f): @functools.wraps(f) def wrapper(*args, **kw): nargs = map(copy.deepcopy, args) nkw = dict(zip(kw.keys(), map(copy.deepcopy, kw.values( return f(*nargs, **nkw) return wrapper Is there any reason not to simplify this to: def copy_args(f): @functools.wraps(f) def wrapper(*args, **kw): nargs = copy.deepcopy(args) nkw = copy.deepcopy(kw) return f(*nargs, **nkw) return wrapper It means you will copy the keys as well, however they will (almost) certainly be strings which is effectively a no-op. Note that this will always work, whereas the decorator.decorator version will break if the decorated function happens to take a keyword argument named f. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 10:34 AM, Chris Kaynor ckay...@zindagigames.com wrote: Is there any reason not to simplify this to: def copy_args(f): @functools.wraps(f) def wrapper(*args, **kw): nargs = copy.deepcopy(args) nkw = copy.deepcopy(kw) return f(*nargs, **nkw) return wrapper No reason, good call. It means you will copy the keys as well, however they will (almost) certainly be strings which is effectively a no-op. I think the keys will certainly be strings. Is there any scenario where they might not be? -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
Henry Olders wrote: [...] what I want is a function that is free of side effects [...] Shoot, that's easy! Just write your function to not have any! ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
Henry Olders wrote: Clearly, making a copy within the function eliminates the possibility of the side effects caused by passing in mutable objects. Would having the compiler/interpreter do this automatically make python so much different? It would be a different language. ~Ethan~ -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
I was thinking you could do something strange like: kw = {object(): None} def test(**kw): print kw test(**kw) however, upon testing it (in Python 2.6), I found that it errors while trying to unpack the kw dict stating that they must all be strings. Perhaps making a custom class derived off basestring, str, unicode, or bytes might allow some oddness and possibly slightly worse performance. Chris On Tue, May 31, 2011 at 10:10 AM, Ian Kelly ian.g.ke...@gmail.com wrote: On Tue, May 31, 2011 at 10:34 AM, Chris Kaynor ckay...@zindagigames.com wrote: Is there any reason not to simplify this to: def copy_args(f): @functools.wraps(f) def wrapper(*args, **kw): nargs = copy.deepcopy(args) nkw = copy.deepcopy(kw) return f(*nargs, **nkw) return wrapper No reason, good call. It means you will copy the keys as well, however they will (almost) certainly be strings which is effectively a no-op. I think the keys will certainly be strings. Is there any scenario where they might not be? -- http://mail.python.org/mailman/listinfo/python-list -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Wed, Jun 1, 2011 at 3:16 AM, Ian Kelly ian.g.ke...@gmail.com wrote: There is no decorator module in the standard library. This must be some third-party module. The usual way to do this would be: Yes, but its very useful for decorators and provides some not-readily-available functionality. http://pypi.python.org/pypi/decorator/3.3.1 Note that this will always work, whereas the decorator.decorator version will break if the decorated function happens to take a keyword argument named f. No, it will not. Its the magic of decorator library, it is signature-preserving, while your variant breaks function signature and causes problems to any code that relies on signatures (happens with Pylons, for example). @copy_args ... def test(a, f=None): ... print f ... test([], f=123) 123 Basically decorator.decorator uses exec to create new function, with signature of function you pass to your decorator, so it does not matter what names you used for args in decorator itself. -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 6:04 PM, Daniel Kluev dan.kl...@gmail.com wrote: On Wed, Jun 1, 2011 at 3:16 AM, Ian Kelly ian.g.ke...@gmail.com wrote: There is no decorator module in the standard library. This must be some third-party module. The usual way to do this would be: Yes, but its very useful for decorators and provides some not-readily-available functionality. http://pypi.python.org/pypi/decorator/3.3.1 Note that this will always work, whereas the decorator.decorator version will break if the decorated function happens to take a keyword argument named f. No, it will not. Its the magic of decorator library, it is signature-preserving, while your variant breaks function signature and causes problems to any code that relies on signatures (happens with Pylons, for example). Ah, I see. I assumed it was much simpler than it is. I found a way to break it with Python 3, though: @copy_args ... def test(*, f): ... return f ... test(f=1) Traceback (most recent call last): File stdin, line 1, in module File string, line 2, in test File stdin, line 6, in copy_args TypeError: test() needs keyword-only argument f The interesting thing here is that the decorated function has exactly the correct function signature; it just doesn't work. Cheers, Ian -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
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
Re: scope of function parameters (take two)
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
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 11:28 AM, Henry Olders henry.old...@mcgill.ca wrote: 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 You still mis-reading docs and explanations you received from the list. Let me try again. First, there are objects and names. Calling either of them as 'variables' is leading to this mis-understanding. Name refers to some object. Object may be referenced by several names or none. Second, when you declare function `def somefunc(a, b='c')` a and b are both local to this function. Even if there are some global a and b, they are 'masked' in somefunc scope. Docs portion you cited refer to other situation, when there is no clear indicator of 'locality', like this: def somefunc(): print a In this - and only in this - case a is considered global. Third, when you do function call like somefunc(obj1, obj2) it uses call-by-sharing model. It means that it assigns exactly same object, that was referenced by obj1, to name a. So both obj1 and _local_ a reference same object. Therefore when you modify this object, you can see that obj1 and a both changed (because, in fact, obj1 and a are just PyObject*, and point to exactly same thing, which changed). However, if you re-assign local a or global obj1 to other object, other name will keep referencing old object: obj1 = [] def somefunc(a): a.append(1) # 'a' references to the list, which is referenced by obj1, and calls append method of this list, which modifies itself in place global obj1 obj1 = [] # 'a' still references to original list, which is [1] now, it have no relation to obj1 at all somefunc(obj1) -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On 5/30/2011 8:28 PM, Henry Olders wrote: Sadly, I feel that the main issue that I was trying to address, has not been dealt with. False. Please go back and read what I and others wrote before. ... 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) You would like Python to be the way it is. Fine. For the Nth time, PARAMATER NAMES ARE LOCAL NAMES. Period. but NOT global unless explicitly defined as global. PARAMETER NAMES **CANNOT** BE DEFINED AS GLOBAL. def f(a): global a SyntaxError: name 'a' is parameter and global Again, go back and reread what I and other wrote. I believe that you are, in part, hypnotized by the work 'variable'. Can you define the word? There are 10 to 20 possible variations, and yours is probably wrong for Python. 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. From 'import this': Namespaces are one honking great idea -- let's do more of those! Python is loaded with namespaces. 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). Python is lexically scoped. another quote from the wikipedia entry for Common Lisp: the use of lexical scope isolates program modules from unwanted interactions. Python is lexically scoped. If making python behave this way is impossible, How do you expect us to respond when you say Please make Python the way it is.? Or is you say If making Python the way it is is impossible...? Now, if you actually want Python to drastically change its mode of operation and break most existing programs, do not bother asking. Are there others who feel as I do that a function parameter should always be local to the function? Yes, we all do, and they are. -- Terry Jan Reedy -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 12:30 PM, Terry Reedy tjre...@udel.edu wrote: Again, go back and reread what I and other wrote. I believe that you are, in part, hypnotized by the work 'variable'. Can you define the word? There are 10 to 20 possible variations, and yours is probably wrong for Python. On a sidenote, I wonder what is the reason to keep word 'variable' in python documentation at all. I believe word 'name' represents concept better, and those, who come from other languages, would be less likely to associate wrong definitions with it. -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 10:28 AM, Henry Olders henry.old...@mcgill.ca wrote: 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). Side point, on variable scope. There is a philosophical split between declaring variables and not declaring them. Python is in the latter camp; you are not required to put int a; char *b; float c[4]; before you use the integer, string, and list/array variables a, b, and c. This simplifies code significantly, but forces the language to have an unambiguous scoping that doesn't care where you assign to a variable. Example: def f(): x=1 # x is function-scope if cond: # cond is global x=2 # Same function-scope x as above print(x) # Function-scope, will be 2 if cond is true This is fine, and is going to be what you want. Another example: def f(): print(x) # global # way down, big function, you've forgotten what you're doing for x in list_of_x: x.frob() By using x as a loop index, you've suddenly made it take function scope, which stops it from referencing the global. Granted, you shouldn't be using globals with names like 'x', but it's not hard to have duplication of variable names. As a C programmer, I'm accustomed to being able to declare a variable in an inner block and have that variable cease to exist once execution leaves that block; but that works ONLY if you declare the variables where you want them. Infinitely-nested scoping is simply one of the casualties of a non-declarative language. Chris Angelico -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 2:05 PM, Chris Angelico ros...@gmail.com wrote: Infinitely-nested scoping is simply one of the casualties of a non-declarative language. Well, this is not accurate, as you can have 'infinitely-nested scoping' in python, in form of nested functions. For example, you can use map(lambda x: expressions with x, including other map/filter/reduce/lambda's, list_of_x), and you will have your isolated scopes. Although due to lambdas supporting only expressions, following this style leads to awkward and complicated code (and/or instead if, map instead for, and so on). -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 1:18 PM, Daniel Kluev dan.kl...@gmail.com wrote: On Tue, May 31, 2011 at 2:05 PM, Chris Angelico ros...@gmail.com wrote: Infinitely-nested scoping is simply one of the casualties of a non-declarative language. Well, this is not accurate, as you can have 'infinitely-nested scoping' in python, in form of nested functions. For example, you can use map(lambda x: expressions with x, including other map/filter/reduce/lambda's, list_of_x), and you will have your isolated scopes. Although due to lambdas supporting only expressions, following this style leads to awkward and complicated code (and/or instead if, map instead for, and so on). That's an incredibly messy workaround, and would get ridiculous if you tried going many levels in. It's like saying that a C-style 'switch' statement can be implemented in Python using a dictionary of lambdas... and then trying to implement fall-through. But you're right; a lambda does technically create something of a nested scope - albeit one in which the only internal variables are its parameters. Chris Angelico -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Mon, May 30, 2011 at 5:28 PM, Henry Olders henry.old...@mcgill.cawrote: 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. If you don't want any globals other than callables and modules and builtins, then don't define any. I normally code that way, other than an infrequent (EG) HAVE_CSTRINGIO global or similar (which is module-global, not program-global) - that is, for variables describing what sorts of optional modules are available. Be careful not to conflate global scoping or global lifetime, with mutability or pure, side-effect-free functions (callables). It sounds like what you want is immutability and/or freedom from side effects, which is found most often in (pure) functional languages - which is not what Python is, nor does it attempt to be so. In Python, and in many other languages, if you pass a scalar (or more generally, an object of an immutable type) to a function, and then change the scalar in that function, you only change the scalar within that function, not within the caller. However, if you pass an aggregate type like a list (array) or dictionary (hash table), then the formal argument itself that you've passed is still only changeable within that function, however what it points off at _is_ changeable via that formal argument. This is of course because otherwise passing a 1 gigabyte dictionary to a function would either have to copy the whole dictionary, or implement some sort of Copy-on-Write semantics, or make it somehow readonly. If you need side effect-free functions in Python, you'd probably best copy your aggregates, EG: import copy def main(): a = ['a list','with','three elements'] print a print fnc1(a) print a def fnc1(b): b = copy.deepcopy(b) return fnc2(b) def fnc2(c): c = copy.deepcopy(c) c[1] = 'having' return c main() Or use Haskell. Please don't try to turn Python into Haskell. Each has its own interesting tradeoffs, and we don't really need two Pythons, and we don't really need two Haskells. HTH. -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Mon, 30 May 2011 20:28:34 -0400, Henry Olders wrote: 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 They are. (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). for loop variables are local to the function, by design. List comprehension variables leak outside the comprehension. That is an accident that is fixed in Python 3. Generator expression variables never leaked. 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. [...] 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. Then you haven't understood the problem at all. 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? How else would the functions be found if they were ONLY treated as local? Consider this code: def spam(): print a_name print len(a_name) This includes two names: a_name and len. They both follow the same lookup rules. Functions in Python are first-class values, just like ints, strings, or any other type. You don't want spam() to see any global a_name without it being declared. But how then can it see len? Don't think that Python could change the rules depending on whether you're calling a name or not. Consider this: def spam(): print a_name print a_name(len) Do you expect the first lookup to fail, and the second to succeed? 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. They are. Always have been, always will be. This would prevent the sort of problems that I encountered as described in my original post. No it wouldn't. You are confused by what you are seeing, and interpreting it wrongly. I believe that what you want is pass-by-value semantics, in the old- school Pascal sense, where passing a variable to a function makes a copy of it. This is not possible in Python. As a design principle, Python never copies objects unless you as it to. 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. Of course. You could create a language that supports any passing models you want. Pascal and VB support pass-by-value (copy on pass) and pass- by-reference. Algol supports pass-by-value and (I think) pass-by-name. There's no reason why you couldn't create a language to support pass-by- value and pass-by-object. Whether this is a good idea is another story. However, that language is not Python. 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. Er, yes? That already happens. 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. You keep bring up the function parameter list as if that made a difference. It doesn't. Perhaps this will enlighten you: alist = [1, 2, 3, 4] blist = alist blist[0] = -999 alist [-999, 2, 3, 4] Passing alist to a function is no different to any other name binding. It doesn't make a copy of the list, it doesn't pass a reference to the name alist, it passes the same object to a new scope. 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. Function parameters are never global. You are misinterpreting what you see if you think they are. [...] 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? They are. You are misinterpreting what you see. -- Steven -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Dienstag 31 Mai 2011, Henry Olders wrote: 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. the parameter is local but it points to an object from an outer scope - that could be the scope of the calling function or maybe the global scope. So if you change the value of this parameter, you change that object from outer scope. But the parameter itself is still local. If you do def fnc2(c): c = 5 the passed object will not be changed, c now points to another object. This is different from other languages where the global c would change (when passing c by reference) what you really seem to want is that a function by default cannot have any side effects (you have a side effect if a function changes things outside of its local scope). But that would be a very different language than python did you read the link Steven gave you? http://mail.python.org/pipermail/tutor/2010-December/080505.html -- Wolfgang -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
Am 31.05.2011 02:28 schrieb Henry Olders: 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? Not for the builtins, but for the global ones. Suppose you have a module def f(x): return 42 def g(x, y): return f(x) + f(y) Would you really want to need a global f inside g? Besides, this doesn't have to do with your original problem at all. Even then, a def h(x): x.append(5) return x would clobber the given object, because x is just a name for the same object which the caller has. 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) They are - in terms of name binding. In Python, you always have objects which can be referred to from a variety of places under different names. Maybe what you want are immutable objects (tuples) instead of mutable ones (lists)... 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 Again: It is the way here. Think of C: there you can have a int f(int * x) { *x = 42; return x; } The scope of the variable x is local here. Same in Python. The object referred to by *x is somewhere else, by design. Same in Python. If making python behave this way is impossible, then I will just have to live with it. Even if I still think that you are confusing scope of a name binding and scope of an object, it is a conceptual thing. Surely it would have been possible to do otherwise, but then it would be a different language. Objects can be mutable, period. In MATLAB, e.g., you have what you desire here: you always have to pass your object around and get another ne back, even if you just add or remove a field of a struct or change the value of a field. HTH, Thomas -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
Daniel Kluev dan.kl...@gmail.com writes: On a sidenote, I wonder what is the reason to keep word 'variable' in python documentation at all. I believe word 'name' represents concept better, and those, who come from other languages, would be less likely to associate wrong definitions with it. I agree, but the term “variable” is used freely within the Python development team to refer to Python's name-to-object bindings, and that usage isn't likely to stop through our efforts. So the burden is unfortunately on us to teach each newbie that this often-used term means something other than what they might expect. -- \ “In case you haven't noticed, [the USA] are now almost as | `\ feared and hated all over the world as the Nazis were.” —Kurt | _o__) Vonnegut, 2004 | Ben Finney -- http://mail.python.org/mailman/listinfo/python-list
Re: scope of function parameters (take two)
On Tue, May 31, 2011 at 4:13 PM, Wolfgang Rohdewald wolfg...@rohdewald.de wrote: what you really seem to want is that a function by default cannot have any side effects (you have a side effect if a function changes things outside of its local scope). But that would be a very different language than python This can be done in Python (to some degree), like this @copy_args def somefunc(a, b, c): ... where copy_args would explicitly call deepcopy() on all args passed to the function. Or, to save some performance, wrap them in some CopyOnEdit proxy (although this is tricky, as getattr/getitem can modify object too if class overrides them). Obviously it would not save you from functions which use global/globals() or some other ways to change state outside their scope. -- With best regards, Daniel Kluev -- http://mail.python.org/mailman/listinfo/python-list