Simulating Pointers in Python

Simulating Pointers in Python

This can be done explicitly.

class ref:
def __init__(self, obj): self.obj = obj
def get(self): return self.obj
def set(self, obj): self.obj = obj

a = ref([1, 2])
b = a
print(a.get()) # => [1, 2]
print(b.get()) # => [1, 2]

b.set(2)
print(a.get()) # => 2
print(b.get()) # => 2

simulating pointer like behavior for python class attribute

You could just set obj.b as a property:

class A:
def __init__(self, value):
self.a = value

@property
def b(self):
return self.a

obj = A('banana')
# now changing my mind
obj.a = 'apple'
print(obj.b) # apple

Of course there's a little more to properties than that. For example if you try to do something like this:

obj.b = 'orange'

It will fail because you can't set that property. But this

obj.a = 'orange'

Would always work, and this test would always be True:

obj.a == obj.b

A working example in the console:

>>> class A:
... def __init__(self, value):
... self.a = value
... @property
... def b(self):
... return self.a
...
>>> a = A('apple')
>>> a.a
'apple'
>>> a.b
'apple'
>>> a.a = 'orange'
>>> a.b
'orange'
>>> a.b = 'hello'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Pointers in Python?

There's no way you can do that changing only that line. You can do:

a = [1]
b = a
a[0] = 2
b[0]

That creates a list, assigns the reference to a, then b also, uses the a reference to set the first element to 2, then accesses using the b reference variable.

How do I go about simulating the equivalent of pass-by-reference in Python?

Based on the comments, your goal is to get back the return status of a function that you don't call directly, and you want to avoid globals. In C you'd have no choice but to use a reference, but in python you have much more flexibility than just locals and (C-style) globals: You can use "closures" to let your callback assign to a local variable directly.

In Python 3

If you use python 3, you can do this straightforwardly with the nonlocal keyword. The simplest case is when you define your callback on the spot:

myfunction():
x = None
def callback():
nonlocal x # Python 3 only
x = 5

gtk.somefunction(callback) # Executes callback()
print "My callback returned", x

But your callback is probably defined elsewhere, or called from lots of different places? No problem, just define on the spot a wrapper that captures the return value of the real callback:

def real_callback():
return 11

def myfunction():
x = 0

def wrapper():
nonlocal x # Python 3 only
x = real_callback()

gtk.somefunction(wrapper)
print "my callback returned", x

This can be obscured by turning wrapper into decorator, but that's a different matter.

Python 2 solution

In python 2 there's no nonlocal statement, and implicit closures are read-only: If you try the above without the nonlocal statement, you get an error. You can assign to a variable if you declare it global, and that's all. So, some trickery is necessary:

First, the function locals() returns a dictionary with all the variables of the local context. locals()['x'] is the local variable x. But locals() is normally read-only. Fortunately there's a nice (or terrible) work-around: For its own reasons, exec disables the optimization that renders locals() read-only... and, it turns out, it stays disabled for the lifetime of the calling function! (Tested on Python 2.6.6, YMMV. If it doesn't work, try exec "a = 0" instead). So, you can do it like this:

def wrapper(callback, context, varname):
def _callback():
context[varname] = callback()
return _callback

def mycode():
exec ""
some_library_function(wrapper(real_callback, locals(), 'z'))
print "The callback returned", z

Is this preferable to just using a mutable container for your return value? That's a matter of taste, I guess. But you can use the same wrapper any number of times, so in a sense it's cleaner than the python 3 solution... if you ignore the magic exec.

How to implement pointers in Python? (or any similar solution else)

Python doesn't need pointers in order to achieve this as every variable is a reference to an object. These references are slightly different from C++ references, in that they can be assigned to - much like pointers in C++.

So to achieve what you're looking for, you'd just need to do something like this:

class A(object):
def __init__( self, connections, sum ):
self.connections = connections
self.sum = sum

def passToConnections( self, index ):
self.connections[ index ].receive( self.sum )

def receive( self, input ):
self.sum += input

And just to prove that this works as expected:

>>> a1 = A( [], 0 )
>>> a2 = A( [], 0 )
>>> a3 = A( [ a1, a2 ], 10 )
>>> a3.passToConnections( 0 )
>>> a3.passToConnections( 1 )
>>> a3.passToConnections( 1 )
>>> print a1.sum
10
>>> print a2.sum
20

So as you can see we have altered the original objects a1 and a2 by calling through to them via the references in a3



Related Topics



Leave a reply



Submit