I know Python doesn’t have pointers, but is there a way to have this yield 2 instead

>>> a = 1
>>> b = a # modify this line somehow so that b "points to" a
>>> a = 2
>>> b
1

?


Here’s an example: I want form.data['field'] and form.field.value to always have the same value. It’s not completely necessary, but I think it would be nice.


In PHP, for example, I can do this:

<?php

class Form {
    public $data = [];
    public $fields;

    function __construct($fields) {
        $this->fields = $fields;
        foreach($this->fields as &$field) {
            $this->data[$field['id']] = &$field['value'];
        }
    }
}

$f = new Form([
    [
        'id' => 'fname',
        'value' => 'George'
    ],
    [
        'id' => 'lname',
        'value' => 'Lucas'
    ]
]);

echo $f->data['fname'], $f->fields[0]['value']; # George George
$f->data['fname'] = 'Ralph';
echo $f->data['fname'], $f->fields[0]['value']; # Ralph Ralph

Output:

GeorgeGeorgeRalphRalph

ideone


Or like this in C++ (I think this is right, but my C++ is rusty):

#include <iostream>
using namespace std;

int main() {
    int* a;
    int* b = a;
    *a = 1;
    cout << *a << endl << *b << endl; # 1 1

    return 0;
}

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.

I want form.data['field'] and
form.field.value to always have the
same value

This is feasible, because it involves decorated names and indexing — i.e., completely different constructs from the barenames a and b that you’re asking about, and for with your request is utterly impossible. Why ask for something impossible and totally different from the (possible) thing you actually want?!

Maybe you don’t realize how drastically different barenames and decorated names are. When you refer to a barename a, you’re getting exactly the object a was last bound to in this scope (or an exception if it wasn’t bound in this scope) — this is such a deep and fundamental aspect of Python that it can’t possibly be subverted. When you refer to a decorated name x.y, you’re asking an object (the object x refers to) to please supply “the y attribute” — and in response to that request, the object can perform totally arbitrary computations (and indexing is quite similar: it also allows arbitrary computations to be performed in response).

Now, your “actual desiderata” example is mysterious because in each case two levels of indexing or attribute-getting are involved, so the subtlety you crave could be introduced in many ways. What other attributes is form.field suppose to have, for example, besides value? Without that further .value computations, possibilities would include:

class Form(object):
   ...
   def __getattr__(self, name):
       return self.data[name]

and

class Form(object):
   ...
   @property
   def data(self):
       return self.__dict__

The presence of .value suggests picking the first form, plus a kind-of-useless wrapper:

class KouWrap(object):
   def __init__(self, value):
       self.value = value

class Form(object):
   ...
   def __getattr__(self, name):
       return KouWrap(self.data[name])

If assignments such form.field.value = 23 is also supposed to set the entry in form.data, then the wrapper must become more complex indeed, and not all that useless:

class MciWrap(object):
   def __init__(self, data, k):
       self._data = data
       self._k = k
   @property
   def value(self):
       return self._data[self._k]
   @value.setter
   def value(self, v)
       self._data[self._k] = v

class Form(object):
   ...
   def __getattr__(self, name):
       return MciWrap(self.data, name)

The latter example is roughly as close as it gets, in Python, to the sense of “a pointer” as you seem to want — but it’s crucial to understand that such subtleties can ever only work with indexing and/or decorated names, never with barenames as you originally asked!

It’s not a bug, it’s a feature 🙂

When you look at the ‘=’ operator in Python, don’t think in terms of assignment. You don’t assign things, you bind them. = is a binding operator.

So in your code, you are giving the value 1 a name: a. Then, you are giving the value in ‘a’ a name: b. Then you are binding the value 2 to the name ‘a’. The value bound to b doesn’t change in this operation.

Coming from C-like languages, this can be confusing, but once you become accustomed to it, you find that it helps you to read and reason about your code more clearly: the value which has the name ‘b’ will not change unless you explicitly change it. And if you do an ‘import this’, you’ll find that the Zen of Python states that Explicit is better than implicit.

Note as well that functional languages such as Haskell also use this paradigm, with great value in terms of robustness.

Yes! there is a way to use a variable as a pointer in python!

I am sorry to say that many of answers were partially wrong. In principle every equal(=) assignation shares the memory address (check the id(obj) function), but in practice it is not such. There are variables whose equal(“=”) behaviour works in last term as a copy of memory space, mostly in simple objects (e.g. “int” object), and others in which not (e.g. “list”,”dict” objects).

Here is an example of pointer assignation

dict1 = {'first':'hello', 'second':'world'}
dict2 = dict1 # pointer assignation mechanism
dict2['first'] = 'bye'
dict1
>>> {'first':'bye', 'second':'world'}

Here is an example of copy assignation

a = 1
b = a # copy of memory mechanism. up to here id(a) == id(b)
b = 2 # new address generation. therefore without pointer behaviour
a
>>> 1

Pointer assignation is a pretty useful tool for aliasing without the waste of extra memory, in certain situations for performing comfy code,

class cls_X():
   ...
   def method_1():
      pd1 = self.obj_clsY.dict_vars_for_clsX['meth1'] # pointer dict 1: aliasing
      pd1['var4'] = self.method2(pd1['var1'], pd1['var2'], pd1['var3'])
   #enddef method_1
   ...
#endclass cls_X

but one have to be aware of this use in order to prevent code mistakes.

To conclude, by default some variables are barenames (simple objects like int, float, str,…), and some are pointers when assigned between them (e.g. dict1 = dict2). How to recognize them? just try this experiment with them. In IDEs with variable explorer panel usually appears to be the memory address (“@axbbbbbb…”) in the definition of pointer-mechanism objects.

I suggest investigate in the topic. There are many people who know much more about this topic for sure. (see “ctypes” module). I hope it is helpful. Enjoy the good use of the objects! Regards, José Crespo

>> id(1)
1923344848  # identity of the location in memory where 1 is stored
>> id(1)
1923344848  # always the same
>> a = 1
>> b = a  # or equivalently b = 1, because 1 is immutable
>> id(a)
1923344848
>> id(b)  # equal to id(a)
1923344848

As you can see a and b are just two different names that reference to the same immutable object (int) 1. If later you write a = 2, you reassign the name a to a different object (int) 2, but the b continues referencing to 1:

>> id(2)
1923344880
>> a = 2
>> id(a)
1923344880  # equal to id(2)
>> b
1           # b hasn't changed
>> id(b)
1923344848  # equal to id(1)

What would happen if you had a mutable object instead, such as a list [1]?

>> id([1])
328817608
>> id([1])
328664968  # different from the previous id, because each time a new list is created
>> a = [1]
>> id(a)
328817800
>> id(a)
328817800 # now same as before
>> b = a
>> id(b)
328817800  # same as id(a)

Again, we are referencing to the same object (list) [1] by two different names a and b. However now we can mutate this list while it remains the same object, and a, b will both continue referencing to it

>> a[0] = 2
>> a
[2]
>> b
[2]
>> id(a)
328817800  # same as before
>> id(b)
328817800  # same as before

From one point of view, everything is a pointer in Python. Your example works a lot like the C++ code.

int* a = new int(1);
int* b = a;
a = new int(2);
cout << *b << endl;   // prints 1

(A closer equivalent would use some type of shared_ptr<Object> instead of int*.)

Here’s an example: I want
form.data[‘field’] and
form.field.value to always have the
same value. It’s not completely
necessary, but I think it would be
nice.

You can do this by overloading __getitem__ in form.data‘s class.

This is a python pointer (different of c/c++)

>>> a = lambda : print('Hello')
>>> a
<function <lambda> at 0x0000018D192B9DC0>
>>> id(a) == int(0x0000018D192B9DC0)
True
>>> from ctypes import cast, py_object
>>> cast(id(a), py_object).value == cast(int(0x0000018D192B9DC0), py_object).value
True
>>> cast(id(a), py_object).value
<function <lambda> at 0x0000018D192B9DC0>
>>> cast(id(a), py_object).value()
Hello

I don’t know if my comment will help or not but if you want to use pointers in python, you can use dictionaries instead of variables

Let’s say in your example will be

a = {'value': 1}

b = {'value': 2}

then you changed a to 2

a['value'] = 2

print(b) #{'value': 2}

I wrote the following simple class as, effectively, a way to emulate a pointer in python:

class Parameter:
    """Syntactic sugar for getter/setter pair
    Usage:

    p = Parameter(getter, setter)

    Set parameter value:
    p(value)
    p.val = value
    p.set(value)

    Retrieve parameter value:
    p()
    p.val
    p.get()
    """
    def __init__(self, getter, setter):
        """Create parameter

        Required positional parameters:
        getter: called with no arguments, retrieves the parameter value.
        setter: called with value, sets the parameter.
        """
        self._get = getter
        self._set = setter

    def __call__(self, val=None):
        if val is not None:
            self._set(val)
        return self._get()

    def get(self):
        return self._get()

    def set(self, val):
        self._set(val)

    @property
    def val(self):
        return self._get()

    @val.setter
    def val(self, val):
        self._set(val)

Here’s an example of use (from a jupyter notebook page):

l1 = list(range(10))
def l1_5_getter(lst=l1, number=5):
    return lst[number]

def l1_5_setter(val, lst=l1, number=5):
    lst[number] = val

[
    l1_5_getter(),
    l1_5_setter(12),
    l1,
    l1_5_getter()
]

Out = [5, None, [0, 1, 2, 3, 4, 12, 6, 7, 8, 9], 12]

p = Parameter(l1_5_getter, l1_5_setter)

print([
    p(),
    p.get(),
    p.val,
    p(13),
    p(),
    p.set(14),
    p.get()
])
p.val = 15
print(p.val, l1)

[12, 12, 12, 13, 13, None, 14]
15 [0, 1, 2, 3, 4, 15, 6, 7, 8, 9]

Of course, it is also easy to make this work for dict items or attributes of an object. There is even a way to do what the OP asked for, using globals():

def setter(val, dict=globals(), key='a'):
    dict[key] = val

def getter(dict=globals(), key='a'):
    return dict[key]

pa = Parameter(getter, setter)
pa(2)
print(a)
pa(3)
print(a)

This will print out 2, followed by 3.

Messing with the global namespace in this way is kind of transparently a terrible idea, but it shows that it is possible (if inadvisable) to do what the OP asked for.

The example is, of course, fairly pointless. But I have found this class to be useful in the application for which I developed it: a mathematical model whose behavior is governed by numerous user-settable mathematical parameters, of diverse types (which, because they depend on command line arguments, are not known at compile time). And once access to something has been encapsulated in a Parameter object, all such objects can be manipulated in a uniform way.

Although it doesn’t look much like a C or C++ pointer, this is solving a problem that I would have solved with pointers if I were writing in C++.

The following code emulates exactly the behavior of pointers in C:

from collections import deque # more efficient than list for appending things
pointer_storage = deque()
pointer_address = 0

class new:    
    def __init__(self):
        global pointer_storage    
        global pointer_address

        self.address = pointer_address
        self.val = None        
        pointer_storage.append(self)
        pointer_address += 1


def get_pointer(address):
    return pointer_storage[address]

def get_address(p):
    return p.address

null = new() # create a null pointer, whose address is 0    

Here are examples of use:

p = new()
p.val="hello"
q = new()
q.val = p
r = new()
r.val = 33

p = get_pointer(3)
print(p.val, flush = True)
p.val = 43
print(get_pointer(3).val, flush = True)

But it’s now time to give a more professional code, including the option of deleting pointers, that I’ve just found in my personal library:

# C pointer emulation:

from collections import deque # more efficient than list for appending things
from sortedcontainers import SortedList #perform add and discard in log(n) times


class new:      
    # C pointer emulation:
    # use as : p = new()
    #          p.val             
    #          p.val = something
    #          p.address
    #          get_address(p) 
    #          del_pointer(p) 
    #          null (a null pointer)

    __pointer_storage__ = SortedList(key = lambda p: p.address)
    __to_delete_pointers__ = deque()
    __pointer_address__ = 0 

    def __init__(self):      

        self.val = None 

        if new.__to_delete_pointers__:
            p = new.__to_delete_pointers__.pop()
            self.address = p.address
            new.__pointer_storage__.discard(p) # performed in log(n) time thanks to sortedcontainers
            new.__pointer_storage__.add(self)  # idem

        else:
            self.address = new.__pointer_address__
            new.__pointer_storage__.add(self)
            new.__pointer_address__ += 1


def get_pointer(address):
    return new.__pointer_storage__[address]


def get_address(p):
    return p.address


def del_pointer(p):
    new.__to_delete_pointers__.append(p)

null = new() # create a null pointer, whose address is 0