[Edu-sig] How does Python do Pointers?

kirby urner kirby.urner at gmail.com
Thu May 8 18:31:59 CEST 2008


On Thu, May 8, 2008 at 8:05 AM, John Posner <jjposner at snet.net> wrote:
>> The sticky-note analogy has a flaw.  You can't stick one
>> note on top of another.  When you say x = y = z, all three variables
>> now point to the object originally pointed to by z.  Then when you
>> say y = 8, y now points to an integer object 8, but x doesn't move
>> with y.  Python's "sticky notes" have a special glue that sticks only
>> to an object, not to another variable.
>
> IMHO it's not a flaw, but a blessing. Extending the "sticky notes" analogy
> by referring to "special glue" is a very intuitive way to explain the
> language feature you describe above -- assigning then reassigning "y". You
> might not like that language feature, but don't place the blame on the
> analogy!
>

A point someone made earlier, and important to emphasize, is that
8 is an object, but doesn't admit state changes i.e. 8.value = 9 is
meaningless.

Type int, like type string, like type tuple, is immutable and therefore
suitable as a key to a dictionary.

If you go x = y = z and then change the state of whatever y points
to or references, then x and z will now both communicate this
change if queried (triggering __getattribute__ or whatever).  However
to say y = 5 is to rebind it to another object entirely, leaving x and
z to stay sticking to 8.

Partly why it's misleading to speak of names as variables is
that shoptalk tends to prevent us from seeing 8 as the *name*
of an immutable object, one for which the name is hardwired
(but feel free to bind, or assign, other not-spoken-for names to
the same object).

Note that 8 .__str__( ) has meaning but 8.__str__( ) does not
(note space after 8 in the first expressioni) because in the latter
case it thinks you're building a decimal then perversely switching
to non-numeric characters.  The parser needs that space to know
you mean to trigger 8's string method, i.e. you're using dot
notation on a name, communicating with its referenced object
per the standard Python "special names" API (the __rib__ cage).

>>  In the classroom we take this a step further and start using a
>>  second color post-it note to start laying the framework for the
>>  concept of namespaces.   If we had been using yellow notes for the
>>  names in the caller's context, we start using green notes for names
>>  in the local namespace of the function.
>
> Excellent! And you could also use multiple sticky-note colors (or multiple
> shapes -- they exist, too) to introduce the concept of typed variables.
> Switching for a moment to that other thread ("Introducing Python at our
> community college"), I don't think that anyone mentioned using "assert" to
> implement typed variables. Example:
>
>    def myfunc(stringparm, listparm, intparm):
>        """
>        function with typed parameters,
>        courtesy of "assert"
>        """
>        # check parameter types
>        assert type(stringparm) is type('abc')
>        assert type(listparm) is type(['a', 'b'])
>        assert type(intparm) is type(123)
>
>        # do the work
>        print "All OK"
>        return
>    # ------------------------------------------
>    >>> f.myfunc('a', range(3), 44)
>    All OK
>
>    >>> f.myfunc(range(3), 44, 'a')
>    Traceback (most recent call last):
>      File "c:\temp\<string>", line 1, in <module>
>      File "c:\temp\f.py", line 6, in myfunc
>        assert type(stringparm) is type('abc')
>    AssertionError:

Good point that type checking is highly doable in Python, a good counter
to those saying Python is only weakly typed or even untyped.  Dynamically
typed is better.  Then of course we say "duck typing" a lot (if it walks
like a duck, talks like a duck...), meaning in Javaspeak that if the interface
is obeyed, then you can treat it as an object of that type, not that interface
obedience is enforced at compile time (one assumes the programmer
knows what a duck is) -- late binding is a runtime feature.

>> * There is one way in which the sticky note analogy breaks down. It
>>   does not accurately portray the internals of a container that
>>   references other objects.  For example if you look back at our
>>   figure on page 127, it gives a false impression that the contents
>>   of the list are contained "within" the list.  For beginners, this
>>   analogy suffices.  Also, in this particular case, the elements of
>>   the list are immutable and so the distinction is less significant.
>
> I'm not sure, but I think the sticky-notes analogy *can* be extended to
> container objects (though it seems that John Zelle doesn't do this in his
> textbook):
>
>  * dictionary: an unordered set of sticky-notes
>  * list: an ordered set of sticky-notes, in which the names on the notes
>    can be changed dynamically by the Python interpreter -- e.g. when a new
>    member of the list is inserted.
>
> I would agree, though, that analogies shouldn't be extended past the point
> where they help students understand the actual language features.
>

In the code below, I build a list of Rod objects, then create a "box" of
rods as a dictionary, keyed by single letters (very *like* names, but not).

In this implementation, Rod objects don't get names of their own,
but have to rely on the built-in hash table mechanism, i.e. the eleven
Rods are not bound to top level names, except indirectly through the
names of collection objects (both "rodobjects" and "box" in this
example):

rodnames = ['z','w','r','g','p','y','d','b','t','B','o']

rodobjects = [
        Rod(length =  0, color = 'none'), # zero rod
        Rod(length =  1, color = 'white'),
        Rod(length =  2, color = 'red'),
        Rod(length =  3, color = 'light green'),
        Rod(length =  4, color = 'pink'),
        Rod(length =  5, color = 'yellow'),
        Rod(length =  6, color = 'dark green'),
        Rod(length =  7, color = 'black'),
        Rod(length =  8, color = 'tan'),
        Rod(length =  9, color = 'blue'),
        Rod(length = 10, color = 'orange')]

box = dict(zip(rodnames, rodobjects))

>
> And just to get a word in on the original question -- how does Python do
> pointers -- what about iterators? From a functional viewpoint, isn't the
> next() operation just like incrementing a pointer?
>
> -John

The interface for the iterator type is pretty simple, in that you need
to have a next method (__next__ under the hood).

In pointer arithemetic, there's this assumption of target memory
already allocated (through malloc) and incrementing a pointer to move
ahead to existing data.

In Python, to next(iterable) is to probably trigger some code that
creates new objects in memory, maybe destroys old ones.  Lots
of objects may change state.  But there's no sense that these
state changes were computed ahead of time, as is more usually
the case in the shoptalk around pointers (when in the C family).

Iterators derive from the idea of lazy or just in time evaluation,
important in many languages.  Generators very closely related
(use them to implement iterators a lot).

Kirby


More information about the Edu-sig mailing list