How to Create a Reference to a Variable in Python

How to create a reference to a variable in python?

No, you cannot. As other answer point out, you can (ab?)use aliasing of mutable objects to achieve a similar effect. However, that's not the same thing as C++ references, and I want to explain what actually happens to avoid any misconceptions.

You see, in C++ (and other languages), a variable (and object fields, and entries in collections, etc.) is a storage location and you write a value (for instance, an integer, an object, or a pointer) to that location. In this model, references are an alias for a storage location (of any kind) - when you assign to a non-reference variable, you copy a value (even if it's just a pointer, it's still a value) to the storage location; when you assign to a reference, you copy to a storage location somewhere else. Note that you cannot change a reference itself - once it is bound (and it has to as soon as you create one) all assignments to it alter not the reference but whatever is referred to.

In Python (and other languages), a variable (and object fields, and entries in collections, etc.) is a just a name. Values are somewhere else (e.g. sprinkled all over the heap), and a variable refers (not in the sense of C++ references, more like a pointer minus the pointer arithmetic) to a value. Multiple names can refer to the same value (which is generally a good thing). Python (and other languages) calls whatever is needed to refer to a value a reference, despite being pretty unrelated to things like C++ references and pass-by-reference. Assigning to a variable (or object field, or ...) simply makes it refer to another value. The whole model of storage locations does not apply to Python, the programmer never handles storage locations for values. All he stores and shuffles around are Python references, and those are not values in Python, so they cannot be target of other Python references.

All of this is independent of mutability of the value - it's the same for ints and lists, for instance. You cannot take a variable that refers to either, and overwrite the object it points to. You can only tell the object to modify parts of itself - say, change some reference it contains.

Is this a more restrictive model? Perhaps, but it's powerful enough most of the time. And when it isn't you can work around it, either with a custom class like the one given below, or (equivalent, but less obvious) a single-element collection.

class Reference:
def __init__(self, val):
self._value = val # just refers to val, no copy

def get(self):
return self._value

def set(self, val):
self._value = val

That still won't allow you to alias a "regular" variable or object field, but you can have multiple variables referring to the same Reference object (ditto for the mutable-singleton-collection alternative). You just have to be careful to always use .get()/.set() (or [0]).

How do I pass a variable by reference?

Arguments are passed by assignment. The rationale behind this is twofold:

  1. the parameter passed in is actually a reference to an object (but the reference is passed by value)
  2. some data types are mutable, but others aren't

So:

  • If you pass a mutable object into a method, the method gets a reference to that same object and you can mutate it to your heart's delight, but if you rebind the reference in the method, the outer scope will know nothing about it, and after you're done, the outer reference will still point at the original object.

  • If you pass an immutable object to a method, you still can't rebind the outer reference, and you can't even mutate the object.

To make it even more clear, let's have some examples.

List - a mutable type

Let's try to modify the list that was passed to a method:

def try_to_change_list_contents(the_list):
print('got', the_list)
the_list.append('four')
print('changed to', the_list)

outer_list = ['one', 'two', 'three']

print('before, outer_list =', outer_list)
try_to_change_list_contents(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['one', 'two', 'three']
got ['one', 'two', 'three']
changed to ['one', 'two', 'three', 'four']
after, outer_list = ['one', 'two', 'three', 'four']

Since the parameter passed in is a reference to outer_list, not a copy of it, we can use the mutating list methods to change it and have the changes reflected in the outer scope.

Now let's see what happens when we try to change the reference that was passed in as a parameter:

def try_to_change_list_reference(the_list):
print('got', the_list)
the_list = ['and', 'we', 'can', 'not', 'lie']
print('set to', the_list)

outer_list = ['we', 'like', 'proper', 'English']

print('before, outer_list =', outer_list)
try_to_change_list_reference(outer_list)
print('after, outer_list =', outer_list)

Output:

before, outer_list = ['we', 'like', 'proper', 'English']
got ['we', 'like', 'proper', 'English']
set to ['and', 'we', 'can', 'not', 'lie']
after, outer_list = ['we', 'like', 'proper', 'English']

Since the the_list parameter was passed by value, assigning a new list to it had no effect that the code outside the method could see. The the_list was a copy of the outer_list reference, and we had the_list point to a new list, but there was no way to change where outer_list pointed.

String - an immutable type

It's immutable, so there's nothing we can do to change the contents of the string

Now, let's try to change the reference

def try_to_change_string_reference(the_string):
print('got', the_string)
the_string = 'In a kingdom by the sea'
print('set to', the_string)

outer_string = 'It was many and many a year ago'

print('before, outer_string =', outer_string)
try_to_change_string_reference(outer_string)
print('after, outer_string =', outer_string)

Output:

before, outer_string = It was many and many a year ago
got It was many and many a year ago
set to In a kingdom by the sea
after, outer_string = It was many and many a year ago

Again, since the the_string parameter was passed by value, assigning a new string to it had no effect that the code outside the method could see. The the_string was a copy of the outer_string reference, and we had the_string point to a new string, but there was no way to change where outer_string pointed.

I hope this clears things up a little.

EDIT: It's been noted that this doesn't answer the question that @David originally asked, "Is there something I can do to pass the variable by actual reference?". Let's work on that.

How do we get around this?

As @Andrea's answer shows, you could return the new value. This doesn't change the way things are passed in, but does let you get the information you want back out:

def return_a_whole_new_string(the_string):
new_string = something_to_do_with_the_old_string(the_string)
return new_string

# then you could call it like
my_string = return_a_whole_new_string(my_string)

If you really wanted to avoid using a return value, you could create a class to hold your value and pass it into the function or use an existing class, like a list:

def use_a_wrapper_to_simulate_pass_by_reference(stuff_to_change):
new_string = something_to_do_with_the_old_string(stuff_to_change[0])
stuff_to_change[0] = new_string

# then you could call it like
wrapper = [my_string]
use_a_wrapper_to_simulate_pass_by_reference(wrapper)

do_something_with(wrapper[0])

Although this seems a little cumbersome.

how to assign variable by reference in python?

The simple answer is that all variables in python are references. Some references are to immutable objects (such as strings, integers etc), and some references are to mutable objects (lists, sets). There is a subtle difference between changing a referenced object's value (such as adding to an existing list), and changing the reference (changing a variable to reference a completely different list).

In your example, you are initially x = o.a making the variable x a reference to whatever o.a is (a reference to 1). When you then do x = 2, you are changing what x references (it now references 2, but o.a still references 1.

A short note on memory management:

Python handles the memory management of all this for you, so if you do something like:

x = "Really_long_string" * 99999
x = "Short string"

When the second statement executes, Python will notice that there are no more references to the "really long string" string object, and it will be destroyed/deallocated.

How do I reference a variable inside a function in a class in python from another external file in python?

If you want var1 then just do

obj = A()
obj.doSomething()
val = obj.var1

How to make all the reference variables None in Python?

I really like your question. Probably this is not exactly what you are looking for, but I have found weakref library. With it you could try to modify your code:

class ListNode:
def __init__(self, val, next_=None):
self.val = val
self.next_ = next_

def get_next(self):
try:
self.next_.check()
except AttributeError: # if self.next_ exists then it does not have 'check' method.
return self.next_
except ReferenceError: # if it does not exists it will raise this exception
return None

Then instead of assigning node.next_ = next_node, you can create weakref:

node = ListNode(1)
next_node = ListNode(2)
node.next_ = weakref.proxy(next_node)

print( next_node == node.next_) # prints True
next_node = None
print(node.get_next()) # prints None

Hope this will help solve your problem!

Edit:
I have also changed the name next to next_ because next is a builtin function

Create a reference to a variable (similar to PHP's =&)?

There is some more magic that can be done in Python (not that I would recommend it and it will require digging on your part ;-), but using a closure may be sufficient for your needs:

get_x = lambda: foo_instance.bar
get_x() # yahoo!

Edit, for those wanting "update support", it's all about the closures:

def wrap_prop (obj, pname):
def _access(*v):
if not len(v):
return getattr(obj, pname)
else
setattr(obj, pname, v[0])
return _access

class z (object):
pass

access = wrap_prop(z(), "bar")
access(20)
access() # yahoo! \o/

Without stepping outside the bounds of normally (for me :-) accepted Python, this could also be written to return an object with forwarding/proxy property, imagine:

access = wrap_prop(z(), "bar")
access.val = 20
access.val # yahoo \o/

Some interesting links:

  • http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
  • http://code.activestate.com/recipes/576787-alias-class-attributes/
  • http://www.faqs.org/docs/diveintopython/dialect_locals.html
  • http://docs.python.org/library/functions.html (see "property")

How to reference variable dynamically in Python?

you can use the eval() function to turn strings into variable:
read on eval

PROJECT_ID = 'test'
BQ_TABLE_NAME_CATEGORIES = 'categories'
BQ_TABLE_NAME_MANUFACTURERS = 'manufacturers'
mylist = [BQ_TABLE_NAME_CATEGORIES, BQ_TABLE_NAME_MANUFACTURERS]
table_categories = PROJECT_ID + '.' + BQ_TABLE_NAME_CATEGORIES
table_manufacturers = PROJECT_ID + '.' + BQ_TABLE_NAME_MANUFACTURERS

for table in mylist:
source_objects=eval('table_{0}'.format(table)) #reference to the correct var
print source_objects

output:

test.categories
test.manufacturers

also as noted in comments, you really shouldn't override list, and use mylist or whatever instead

Python functions call by reference

You can not change an immutable object, like str or tuple, inside a function in Python, but you can do things like:

def foo(y):
y[0] = y[0]**2

x = [5]
foo(x)
print x[0] # prints 25

That is a weird way to go about it, however, unless you need to always square certain elements in an array.

Note that in Python, you can also return more than one value, making some of the use cases for pass by reference less important:

def foo(x, y):
return x**2, y**2

a = 2
b = 3
a, b = foo(a, b) # a == 4; b == 9

When you return values like that, they are being returned as a Tuple which is in turn unpacked.

edit:
Another way to think about this is that, while you can't explicitly pass variables by reference in Python, you can modify the properties of objects that were passed in. In my example (and others) you can modify members of the list that was passed in. You would not, however, be able to reassign the passed in variable entirely. For instance, see the following two pieces of code look like they might do something similar, but end up with different results:

def clear_a(x):
x = []

def clear_b(x):
while x: x.pop()

z = [1,2,3]
clear_a(z) # z will not be changed
clear_b(z) # z will be emptied


Related Topics



Leave a reply



Submit