473,569 Members | 2,870 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How safe is modifying locals()?

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

One approach that has been suggested is to use locals() and indirect
references to the immutable via the resulting dictionary,

def change(x, y, refs):
x = x + 1
refs[y] = refs[y] + 1

x = 0; y = 0;
change(x, 'y', locals())

The Python documentation gives a warning that modifying the contents of
locals() may not affect local values. Despite the warning, the code
seems to work as desired, at least on Python 2.2.

Does anyone know how safe this approach is, particularly in a
multithreaded environment? Will this work on Jython?

Does anyone have any alternative strategies for trying to achieve the
objective? A "Pythonic" approach such as,

def change(x, y):
x = x + 1
y = y + 1
return y

x = 0; y = 0
y = change(x, y)

Works in a single threaded environment but, because the value of 'y'
changes at the wrong time, with multiple threads there is a possibility
that two users of 'y' could dissagree on its value.

Paul
Paul Paterson
(pa**********@u sers.sourceforg e.net)

vb2py :: A Visual Basic to Python Conversion Toolkit
http://vb2py.sourceforge.net

Jul 18 '05 #1
15 2468

"Paul Paterson" <pa**********@u sers.sourceforg e.net> wrote in message
news:BD******** *************@t wister.austin.r r.com...
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

One approach that has been suggested is to use locals() and indirect
references to the immutable via the resulting dictionary,

def change(x, y, refs):
x = x + 1
refs[y] = refs[y] + 1

x = 0; y = 0;
change(x, 'y', locals())

The Python documentation gives a warning that modifying the contents of locals() may not affect local values. Despite the warning, the code
seems to work as desired, at least on Python 2.2.


At module scope, locals() == globals(). Within a function, locals()
currently is a *copy* of the function's local namespace. So above
only works because you made the call from the global (module) context
and would not if you tested by making call from within a function.

Terry J. Reedy
Jul 18 '05 #2
Terry Reedy wrote:
"Paul Paterson" <pa**********@u sers.sourceforg e.net> wrote in message

The Python documentation gives a warning that modifying the contents


of
locals() may not affect local values. Despite the warning, the code
seems to work as desired, at least on Python 2.2.

At module scope, locals() == globals(). Within a function, locals()
currently is a *copy* of the function's local namespace. So above
only works because you made the call from the global (module) context
and would not if you tested by making call from within a function.


Thanks Terry! I adjusted my tests and now see this behaviour exactly.
The function itself works but the changes do not propogate out to the
calling scope. So this approach of using locals() appears to be dead.

Are there any other approaches?

Paul
Jul 18 '05 #3
Quoth Paul Paterson:
[...]
Does anyone have any alternative strategies for trying to achieve the
objective? A "Pythonic" approach such as,

def change(x, y):
x = x + 1
y = y + 1
return y

x = 0; y = 0
y = change(x, y)

Works in a single threaded environment but, because the value of 'y'
changes at the wrong time, with multiple threads there is a possibility
that two users of 'y' could dissagree on its value.


Even if the simple
y = y + 1
could change the caller's binding, there would be a race condition
-- you'll need a lock anyway. (I'd be a bit surprised if this
were not so in VB as well. Are statements atomic in VB?)

--
Steven Taschuk w_w
st******@telusp lanet.net ,-= U
1 1

Jul 18 '05 #4
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']

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. 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. :-)

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.

Shane
Jul 18 '05 #5
On Fri, 2003-07-25 at 12:28, Paul Paterson wrote:
Thanks Terry! I adjusted my tests and now see this behaviour exactly.
The function itself works but the changes do not propogate out to the
calling scope. So this approach of using locals() appears to be dead.

Are there any other approaches?


Think about what you are trying to do, and try to identify a (mutable)
object that can encapsulate that. Then pass the object, and modify its
instance variables, like:

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def change(p):
p.y = 10

obj = Point(0, 0)
change(obj)
assert obj.y == 10
Maybe this mutable object will simply be the main application object,
and instead of functions you will use methods of that application
object.

Ian

Jul 18 '05 #6
Ian Bicking wrote:
On Fri, 2003-07-25 at 12:28, Paul Paterson wrote:
Thanks Terry! I adjusted my tests and now see this behaviour exactly.
The function itself works but the changes do not propogate out to the
calling scope. So this approach of using locals() appears to be dead.

Are there any other approaches?

Think about what you are trying to do, and try to identify a (mutable)
object that can encapsulate that. Then pass the object, and modify its
instance variables, like:

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def change(p):
p.y = 10

obj = Point(0, 0)
change(obj)
assert obj.y == 10
Maybe this mutable object will simply be the main application object,
and instead of functions you will use methods of that application
object.

Ian


This is a very interesting (and Pythonic) approach, thanks for
suggesting it! This is certainly what I would try to do if I were
writing the code from scratch. It may be possible to construct a
"namespace" type object which gets passed to the function.

VB does have multiple namespaces so a single App object is probably not
feasible but since my parser knows the App structure it can determine
which namespace a variable will be resolved from anyway and just
translate all attempts to access it to the relevant namespace object lookup.

Paul

Jul 18 '05 #7
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

Jul 18 '05 #8
Hi Paul

Paul Paterson wrote:
This is a very interesting (and Pythonic) approach, thanks for
suggesting it! This is certainly what I would try to do if I were
writing the code from scratch. It may be possible to construct a
"namespace" type object which gets passed to the function.


I think the most common way to make a namespace in Python is

class my_namespace: pass
....
my_namespace.a = 'foo'
my_namespace.b = 'bar'

Such namespaces are very similar to dictionaries:

my_namespace = {}
....
my_namespace['a'] = 'foo'
my_namespace['b'] = 'bar'

but the first approach is a bit more readable.

If you need many containers, you could use:

class Container:
pass

c1 = Container()
c2 = Container()
....
c1.foo = 'foo'
c2.foo = 'bar'

Of course, if you have a better name for your container, that's even
better. Think of Ian's Point example. :-)

Stefan

Jul 18 '05 #9
Stefan Schwarzer wrote:
Hi Paul

Paul Paterson wrote:
This is a very interesting (and Pythonic) approach, thanks for
suggesting it! This is certainly what I would try to do if I were
writing the code from scratch. It may be possible to construct a
"namespace" type object which gets passed to the function.

I think the most common way to make a namespace in Python is


<snip nice example of namespace class>

Thanks, the bare namespace class is essentially what I am going to try.

Of course, if you have a better name for your container, that's even
better. Think of Ian's Point example. :-)


I think you may have missed my original post; I am writing a generic VB
to Python converter so generating good names based on code intent would
be pretty tough! Perhaps in v2.0 ;)

My current thinking is (for the orignal example of changing one
variable, 'y' but not another, 'x'),

class Namespace: pas

# ByVal arguments passed directly, ByRef via a namespace
def change(x, byrefs):
x = x + 1
byrefs.y = byrefs.y + 1

ns = Namespace() # The local namespace
ns.x = 0
ns.y = 0
change(ns.x, ns)
# Now ns.x = 0, ns.y = 1
Paul

Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
2071
by: Robert Dodier | last post by:
Hello, I'm interested in introducing new variables into the environment of a Python interpreter or program. In reading through old posts to this newsgroup, I see there is an often-repeating warning against modifying the contents of locals(). Fair enough. However, is there anything wrong with modifying globals() ?
4
2885
by: Chris Newby | last post by:
When accessing, for example, an object stored in the session such as: Session.MyProperty = "Some Value"; Is access to MyObject thread-safe?
6
1775
by: John [H2O] | last post by:
I would like to write a function to write variables to a file and modify a few 'counters'. This is to replace multiple instances of identical code in a module I am writing. This is my approach: def write_vars(D): """ pass D=locals() to this function... """ for key in D.keys(): exec("%s = %s" % (key,D))
0
884
by: Steve Holden | last post by:
John wrote: Note that this code will likely fail to execute if D is some object whose str() method does not return a valid Python expression. Return them as a tuple, using an unpacking assignment to bind the different elements to different names. It's not really obvious why you are trying to replicate the caller's namespace inside this...
0
7693
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main...
0
7605
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8118
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7665
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
7962
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
3651
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
0
3631
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2105
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1207
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.