How safe is modifying locals()?

Paul Paterson paulpaterson at users.sourceforge.net
Fri Jul 25 22:25:20 EDT 2003


Shane Hathaway wrote:

> Paul Paterson wrote:
> 
>> I am trying to find a way to mimic by-reference argument passing for 
>> immutables in Python. I need to do this because I am writing an 
>> automated VB to Python converter.
>>
>> Here's an example of the VB code:
>>
>> Sub Change(ByVal x, ByRef y)
>> x = x+1
>> y = y+1
>> End Sub
>>
>> x = 0: y = 0
>> Change x, y
>> ' Now x should be 0 and y should be 1
> 
> 
> I might put all of the "ByRef" variables in a dictionary that gets 
> passed back to the caller through a hidden argument.
> 
> def change(x, y, _byref):
>   x = x + 1
>   y = _byref['y'] = y + 1
> 
> x = 0; y = 0
> __byref = {'y': y}; change(x, y, __byref); y = __byref['y']
> 

The problem here is that you still have the delayed change to 'y' in the 
caller's scope. Other posts in this thread have made me wonder whether 
this is a problem sepcific to the ByRef topic.

The interesting thing about your approach is that you have an explicit 
step for transmitting changes to y back to the calling scope - which is 
quite nice. In an automated translation, having this explicit is a good 
sign-post for the user to let them know that something important is 
going on.

> At least this relies on nothing magical.  One thing that's still wrong, 
> though, is that you can't embed the change() call in an expression. 
> AFAIK, in Python, assignment to a local variable absolutely requires a 
> statement.  You can get around this by splitting apart the expression 
> and storing the result of the call in another hidden temporary variable.
> 
> Even if you do that, though, exceptions will behave differently in 
> Python than they do in VB.  

Matching VB's exception behaviour is my worst nightmare - but that's 
another story ...

> If an exception occurs in change() after a 
> value has been assigned to 'y', the outer code won't get the value, and 
> it just might affect the behavior of the outer code.  You could fix that 
> with a try: / finally:
> 
> __byref = {'y': y}
> try:
>   change(x, y, __byref)
> finally:
>   y = __byref['y']
> 
> Suddenly it's awfully verbose and ugly, but if variables by reference 
> are rare (as they should be), maybe it's not so bad. :-)

Unfortunately (and to my shock), it seems that ByRef is the *default*! 
It may be the case that using the implications of ByRef are rare and it 
may be possible for me to detect when this is occuring.

> You could go the extreme route and store all variables in dictionaries 
> rather than use local variables, which would allow "true" references, 
> but then you'd kill speed and readability.  Better not do that.

At the end of the day (see my response to Ian) this may in fact be the 
safest approach if you want to match the exact behaviour of the original 
VB code. There will almost certainly be a switch where you can turn this 
off, but then it is up to the programmer to go and fix things which get 
broken. Hopefully it will be possible to try to identify likely hot 
spots automatically.

Paul





More information about the Python-list mailing list