Ruixing Wang Ruixing Wang - 1 year ago 46
Python Question

Changing binding rule for a variable in Python?

My question comes from this page, while I would like to create a pointer(-like thing) for an list element. The element is a primitive value (string) so I have to create a FooWrapper class as that page says.

I know that by setting

one can directly access this value.

class FooWrapper(object):
def __init__(self, value):
self.value = value
def __repr__(self):
return repr(self.value)

>>> bar=FooWrapper('ABC')
>>> bar
>>> bar=FooWrapper(3)
>>> bar

Now I can use it as an reference of string:

>>> L=[3,5,6,9]
>>> L[1]=FooWrapper('ABC')
>>> L
>>> this=L[1]
>>> this.value='BCD'
>>> print(L)

So now I have a pointer-like
for the list element

However it is still inconvenient since I must use
to change its value. While there exists a
method to make
directly return
, is there any similar method to make
to do
? I know this changes the rule of binding.. but anyway, is it possible?

I would also appreciate if there is a better solution for a list element pointer.

Thank you in advance:)

Answer Source

I'm not sure exactly what you are trying to do, but you could do something like:

class FooWrapper(object):
    def __init__(self, value):
         self.value = value
    def __repr__(self):
         return 'FooWrapper(' + repr(self.value) + ')'
    def __str__(self):
        return str(self.value)
    def __call__(self,value):
        self.value = value

Here I got rid of your idea of using __repr__ to hide FooWrapper since I think it a bad idea to hide from the programmer what is happening at the REPL. Instead -- I used __str__ so that when you print the object you will print the wrapped value. The __call__ functions as a default method, which doesn't change the meaning of = but is sort of what you want:

>>> vals = [1,2,3]
>>> vals[1] = FooWrapper("Bob")
>>> vals
[1, FooWrapper('Bob'), 3]
>>> for x in vals: print(x)

>>> this = vals[1]
>>> this(10)
>>> vals
[1, FooWrapper(10), 3]

However, I think it misleading to refer to this as a pointer. It is just a wrapper object, and is almost certain to make dealing with the wrapped object inconvenient.

On Edit: The following is more of a pointer to a list. It allows you to create something like a pointer object with __call__ used to dereference the pointer (when no argument is passed to it) or to mutate the list (when a value is passed to __call__). It also implements a form of p++ called (pp) with wrap-around (though the wrap-around part could of course be dropped):

class ListPointer(object):
    def __init__(self, myList,i=0):
         self.myList = myList
         self.i = i % len(self.myList)

    def __repr__(self):
         return 'ListPointer(' + repr(self.myList) + ',' + str(self.i) + ')'

    def __str__(self):
        return str(self.myList[self.i])

    def __call__(self,*value):
        if len(value) == 0:
            return self.myList[self.i]
            self.myList[self.i] = value[0]

    def pp(self):
        self.i = (self.i + 1) % len(self.myList)

Used like this:

>>> vals = ['a','b','c']
>>> this = ListPointer(vals)
>>> this()
>>> this('d')
>>> vals
['d', 'b', 'c']
>>> this.pp()
>>> this()
>>> print(this)

I think that this is a more transparent way of getting something which acts like a list pointer. It doesn't require the thing pointed to to be wrapped in anything.