[Tutor] Globals?

orbitz orbitz at ezabel.com
Sat Nov 13 23:23:11 CET 2004


The change doesn't happen at all actually:

 >>> def fn(x):
...     def _():
...             x += 1
...             return x
...     return _
...
 >>> blah = fn(2)
 >>> blah()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in _
UnboundLocalError: local variable 'x' referenced before assignment

Here is a CL equiv of what I *think* should happen, unelss someone has a 
godo reason for it not to belike this:

(defun foo (n) (lambda (i) (incf n i)))

Kent Johnson wrote:

> The issue is whether a closure can rebind a variable in the enclosing 
> scope. Python does not allow this except in the special case where the 
> enclosing scope is the global scope - then you can use the global 
> keyword to rebind it.
>
> But I was responding to the message where you said,
>
>> In my opinion, this behavior really sucks too. Like when it comes to 
>> closures.  As far as I know, Python does not *really* support 
>> closures, like you would get with something like lisp. Correct me if 
>> I'm wrong.  This means code like:
>>
>> def fn(x):
>>    def _():
>>       x += 1
>>       return x
>>    return _
>>
>> Will not work, which can be a pain in the ass.
>
>
> Could you explain what behavior you would like to see from this 
> program and why it sucks not to get it? My guess is that the problem 
> is that
>   x += 1
> only rebinds x in the scope of _(), not in the scope of fn(), so the 
> change to x is not persistent.
>
> Kent
>
> orbitz wrote:
>
>> Kent, If i follow what you are saying here, I think you are confusing 
>> dynamic scope with lexical scope in here.  Dynamic scoping tends to 
>> be icky for debugging and usage purposes, and lexical scoping is 
>> generally preferred.
>>
>> If I'm not following what you are saying here properly please correct me
>>
>>
>> Lloyd Kvam wrote:
>>
>>> But integers are immutable.
>>>
>>> If names could be rebound as a side-effect of a function call, you 
>>> would
>>> be creating some difficult to debug connections in your program. If 
>>> you are deliberately creating a special environment for communicating
>>> between functions sharing that environment (closures), it probably 
>>> makes
>>> sense to use a dictionary or class to separate those variable names 
>>> from
>>> the "general" variables.  A list works, since it is mutable.
>>>
>>> I guess I'm not a closure purist.
>>>
>>> On Sat, 2004-11-13 at 15:57, Kent Johnson wrote:
>>>  
>>>
>>>> I think the idea is that x in the enclosing scope should be changed 
>>>> when _ is called. To closure purists :-) a language doesn't have 
>>>> closures if it can't do this.
>>>>
>>>> Python will bind the *values* of variables in an enclosing scope 
>>>> into a closure, which is good enough for many uses :-)
>>>>
>>>> Personally I haven't found much need for 'true' closures. orbitz, 
>>>> can you say why this is such a pain? How would you use a true closure?
>>>>
>>>> A workaround is to store the variable in a list, but it's a bit ugly:
>>>>
>>>> x = [3]
>>>> def fn(x):
>>>>     def _():
>>>>        x[0] += 1
>>>>        return x[0]
>>>>     return _
>>>>
>>>> Kent
>>>>
>>>> Lloyd Kvam wrote:
>>>>  
>>>>
>>>>> It DOES work in current versions of Python, exactly as you coded it.
>>>>>
>>>>> In older Pythons (e.g. 1.52) you would have had to specifying the
>>>>> enclosing variables explicitly
>>>>>     def _(x=x):
>>>>>
>>>>> A lot of old critiques are still present on the web.  wikipedia has a
>>>>> terrific article describing Python that is current (at least 2.3.3).
>>>>>
>>>>> http://en.wikipedia.org/wiki/Python_programming_language
>>>>>
>>>>>
>>>>>
>>>>> On Sat, 2004-11-13 at 14:07, orbitz wrote:
>>>>>
>>>>>    
>>>>>
>>>>>> In my opinion, this behavior really sucks too. Like when it comes 
>>>>>> to closures.  As far as I know, Python does not *really* support 
>>>>>> closures, like you would get with something like lisp. Correct me 
>>>>>> if I'm wrong.  This means code like:
>>>>>>
>>>>>> def fn(x):
>>>>>>   def _():
>>>>>>      x += 1
>>>>>>      return x
>>>>>>   return _
>>>>>>
>>>>>> Will not work, which can be a pain in the ass.
>>>>>>
>>>>>>
>>>>>> Kent Johnson wrote:
>>>>>>
>>>>>>
>>>>>>      
>>>>>>
>>>>>>> Liam,
>>>>>>>
>>>>>>> When you make any assignment to a variable inside a function, 
>>>>>>> Python assumes that the variable is local to the function. Then 
>>>>>>> any use of the variable before it's first assignment is an error.
>>>>>>>
>>>>>>> To force a variable in a function to be global, put a 'global' 
>>>>>>> statement in the function. You need to add
>>>>>>> global badConnectCycle
>>>>>>> to your function getReturns
>>>>>>>
>>>>>>> If you don't make any assignment to a variable, then the global 
>>>>>>> (module) namespace is searched. That is why badUserList works 
>>>>>>> fine - you never assign it, you just access the list methods.
>>>>>>>
>>>>>>> Kent
>>>>>>>
>>>>>>> Liam Clarke wrote:
>>>>>>>
>>>>>>>
>>>>>>>        
>>>>>>>
>>>>>>>> Hi all,
>>>>>>>> Having trouble with something, it is 3:30am in the morning, so 
>>>>>>>> this
>>>>>>>> may be a dumb problem, if so, I apologise.
>>>>>>>>
>>>>>>>> In my prog, there's two variables created right at the get go -
>>>>>>>>
>>>>>>>> import imaplib
>>>>>>>> import email.Parser
>>>>>>>> import os
>>>>>>>> import os.path
>>>>>>>> import datetime
>>>>>>>> import md5
>>>>>>>>           from pause import *
>>>>>>>
>>>>>>>
>>>>>>>        
>>>>>>>
>>>>>>>> badUserList=[]
>>>>>>>> badConnectCycle=0
>>>>>>>>
>>>>>>>> as I want them to be global within this module, so that another 
>>>>>>>> module
>>>>>>>> can pick them out easily.
>>>>>>>>
>>>>>>>> Now, I just added badConnectCycle, badUserList has been there 
>>>>>>>> awhile,
>>>>>>>> and it's used in
>>>>>>>>
>>>>>>>> the function connectToImap which is called by getReturns which is
>>>>>>>> called by main(), and my other module can get it no problem, so
>>>>>>>> badUserList is fine.
>>>>>>>>
>>>>>>>> badConnectCycle... is giving me errors -
>>>>>>>>
>>>>>>>> badConnectCycle is used in getReturns, as so -
>>>>>>>> if session == "NoConnect" :             badConnectCycle += 1
>>>>>>>>           continue
>>>>>>>>
>>>>>>>>
>>>>>>>> function getReturns ends as follows -
>>>>>>>> if badConnectCycle == len(user) and badConnectCycle > 0: return 
>>>>>>>> ("NoConnect","")
>>>>>>>> if badUserList and not sender: return ('NoLogin',"")
>>>>>>>> if matchindex[0] and not sender: return ('NoNew', '')
>>>>>>>> if not sender: return ("NoMatch","")
>>>>>>>> return (sender, msgdata)
>>>>>>>>
>>>>>>>> and it's at that line
>>>>>>>>
>>>>>>>> if badConnectCycle == len(user) and badConnectCycle > 0:
>>>>>>>>
>>>>>>>> that I get this error:
>>>>>>>>
>>>>>>>> UnboundLocalError: local variable 'badConnectCycle' referenced 
>>>>>>>> before
>>>>>>>> assignment.
>>>>>>>>
>>>>>>>> Which is confusing me because badUserList is used within a 
>>>>>>>> function
>>>>>>>> called by getReturns, and I've had no problem with it.
>>>>>>>>
>>>>>>>> Help anyone? Much appreciated if you can.
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>>
>>>>>>>> Liam Clarke
>>>>>>>>           
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> Tutor maillist  -  Tutor at python.org
>>>>>>> http://mail.python.org/mailman/listinfo/tutor
>>>>>>>
>>>>>>>         
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> Tutor maillist  -  Tutor at python.org
>>>>>> http://mail.python.org/mailman/listinfo/tutor
>>>>>>       
>>>>>
>>>>
>>>> _______________________________________________
>>>> Tutor maillist  -  Tutor at python.org
>>>> http://mail.python.org/mailman/listinfo/tutor
>>>>   
>>>
>>
>>
>>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
>



More information about the Tutor mailing list