anything like C++ references?

Bengt Richter bokr at oz.net
Mon Jul 14 14:16:08 EDT 2003


On Mon, 14 Jul 2003 03:40:05 -0000, "Donn Cave" <donn at drizzle.com> wrote:

>On Sun, 2003-07-13 at 20:32, Aahz wrote:
>> In article <mailman.1058126720.6756.python-list at python.org>,
>|> Ian Bicking  <ianb at colorstudy.com> wrote:
>|>>
>|>> (Admittedly, some confusion may occur because these very different
>|>> operations use the same syntax:
>|>>
>|>>  x = 10
>|>>  x[0] = 10
>|>>  obj.x = 10
>|>>
>|>> The second and third are entirely different from the first.)
>|> 
>|> No, they aren't.  They are precisely the same; they just have different
>|> assignment targets.
>|
>| Sure they are different.  The first is a primitive operation binding the
>| variable x.  The second gets x, and calls x.__setitem__(0, 10), and the
>| third is equivalent to setattr(obj, 'x', 10).
Which might turn out to be equivalent to object.__setattr__(obj, 'x', 10)
or obj.__setattribute__('x', 10) or obj.__class__.__dict__['x'].fset(obj, 10) or ...

It depends on what you mean by 'targets'. I argued that the three left hand
expressions all *ultimately* result in some machine level pointer variable being set
in some object's internal representation to point to the representation of the object
resulting from evaluating the right hand side, and in that sense all the assignments
have the same ultimate semantics. Some pointer in some composite object is set to point
to another object.

Depending on the left hand object actually involved, we use different expressions to
retrieve the pointer (and often you have a choice, e.g., x.y or x.__dict__['y'] or getattr(x,'y')
or vars(x).get('y') etc., some of which might not be valid. Even plain x might sometimes be
retrieved by sys._getframe().f_locals.get('x').

>
>I wonder if this is a good example of a mutability thing that really
>is kind of missing to the detriment of Python.
>
>If you want to support user-implemented sequences (as Python does)
>but make Aahz's ``precisely the same'' assertion true in the sense
>you're taking it - then I think the user-implemented indexing function
>would have to return a reference to the index location.
>

I guess you could define something like your *loc below, but you'd have to be
willing to spell it loc.star when you used it.

class Loc(object): #XXX# untested !!
    def __init__(self, theArray, theItem=0): self._theArray=theArray; self._theItem=theItem
    def _get_it(self): return self._theArray[self._theItem]
    def _set_it(self,v): self._theArray[self._theItem] = v
    star = property(_get_it, _set_it)

>   class UserArray:
>       ...
>       def __item__(self, index):
            return Loc(self, index)
>           return &self.internal_array[index]
>
>   userArray[5] = 1
>   (python internal)
>       loc = UserArray.__item__(userArray, 5)
        loc.star = 1
>       *loc = 1
>
>   if userArray[6] == 
>   (python internal)
>       loc = UserArray.__item__(userArray, 6)
        return loc.star 
>       return *loc
>
>There are other places where instead we use some kludge with a
>mutable container type, but in this case I don't think there's
>a way to get around it.  So whether we like the idea or not,
>assignment to a user-implemented sequence doesn't have to involve
>any assignment at all, because Python lacks the "pointer" type
>(or "target" type, if you prefer) that would be required to
>implement that.

Or you could say the implementation is internal and you have
to use the right spellings to effect the semantics indirectly.
I.e., op[i]=newitem spells *p = newitem internally (names obviously not directly related):

int
PyList_SetItem(register PyObject *op, register int i,
               register PyObject *newitem)
{
    ...
    p = ((PyListObject *)op) -> ob_item + i;
    olditem = *p;
    *p = newitem;
    Py_XDECREF(olditem);
    return 0;
}

Regards,
Bengt Richter




More information about the Python-list mailing list