Discussion:
[Tutor] pointer puzzlement
Jim Mooney Py3.4.3winXP
2015-05-07 19:15:42 UTC
Permalink
I find this a bit confusing. Since the ID of K remains the same, so it's
the same object, why isn't it increasing each time. i.e, 20, 30, 40,. I
understand that it's immutable but doesn't that mean K is created each time
in local scope so it should have a different ID each time?

def testid(K=10):
K += 10
return 'the ID is', id(K), K

*** Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600
32 bit (Intel)] on win32. ***
testid()
('the ID is', 505991936, 20)
testid()
('the ID is', 505991936, 20)
testid()
('the ID is', 505991936, 20)
--
Jim
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Emile van Sebille
2015-05-07 20:03:56 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
I find this a bit confusing. Since the ID of K remains the same, so it's
the same object, why isn't it increasing each time. i.e, 20, 30, 40,. I
understand that it's immutable but doesn't that mean K is created each time
in local scope so it should have a different ID each time?
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
id(20)
7515584L
Post by Jim Mooney Py3.4.3winXP
id(10+10)
7515584L
Post by Jim Mooney Py3.4.3winXP
id(19+1)
7515584L


Compare to:

def testid(K=1000000):
K += 10
return 'the ID is', id(K), K


Emile


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Jim Mooney Py3.4.3winXP
2015-05-07 20:54:10 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
K += 10
return 'the ID is', id(K), K
Ah, thanks. I forgot small integers are saved in a table. I was looking at
a demo that pointers to defaults in function parameters are persistent. It
used lists so I tried ints. Although I realized persistence also works for
dicts ;')

def testid(newitem, K={}):
K[newitem] = newitem + 'item'
return 'the ID is', id(K), K
Post by Jim Mooney Py3.4.3winXP
testid('bonk')
('the ID is', 18263656, {'bonk': 'bonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('clonk')
('the ID is', 18263656, {'bonk': 'bonkitem', 'clonk': 'clonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('spam')
('the ID is', 18263656, {'bonk': 'bonkitem', 'clonk': 'clonkitem', 'spam':
'spamitem'})
--
Jim

"What a rotten, failed experiment. I'll start over. Maybe dogs instead of
monkeys this time." --God
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-05-07 21:25:47 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
Ah, thanks. I forgot small integers are saved in a table. I was looking at
a demo that pointers to defaults in function parameters are persistent.
But remember they variables are NOT pointers.
They are keys in a dictionary. Very different.

Also the id() function is implementation dependant so
although it may seem to be a memory address in CPython
it is something else in IronPython and something else
again in Jython. The only thing guaranteed is that
it is a unique id for that object.

As to default parameter values, the default object is
persistent but if you reassign the parameter inside
the function it will obviously lose its binding to
the default object. It will only be reassigned to
it on the next function call (unless it's a generator
function).
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-07 23:57:35 UTC
Permalink
Post by Alan Gauld
Post by Jim Mooney Py3.4.3winXP
Ah, thanks. I forgot small integers are saved in a table. I was looking at
a demo that pointers to defaults in function parameters are persistent.
But remember they variables are NOT pointers.
They are keys in a dictionary. Very different.
Also the id() function is implementation dependant so
although it may seem to be a memory address in CPython
it is something else in IronPython and something else
again in Jython. The only thing guaranteed is that
it is a unique id for that object.
Unique as long as the two objects you're examining exist at the same
time. An id() may be reused once the first object is destroyed. And in
general for CPython that happens a lot for small objects.
Post by Alan Gauld
As to default parameter values, the default object is
persistent but if you reassign the parameter inside
the function it will obviously lose its binding to
the default object. It will only be reassigned to
it on the next function call (unless it's a generator
function).
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-07 23:51:42 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
Post by Jim Mooney Py3.4.3winXP
K += 10
return 'the ID is', id(K), K
Ah, thanks. I forgot small integers are saved in a table. I was looking at
a demo that pointers to defaults in function parameters are persistent.
Python doesn't have pointers, and nothing here is persistent.
Persistence refers to a value surviving multiple invocations of a program.
Post by Jim Mooney Py3.4.3winXP
It
used lists so I tried ints. Although I realized persistence also works for
dicts ;')
K[newitem] = newitem + 'item'
return 'the ID is', id(K), K
Post by Jim Mooney Py3.4.3winXP
testid('bonk')
('the ID is', 18263656, {'bonk': 'bonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('clonk')
('the ID is', 18263656, {'bonk': 'bonkitem', 'clonk': 'clonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('spam')
'spamitem'})
The object is not immutable, so it can change. Therefore the += does an
in-place change, and you keep the same id.
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-08 01:42:35 UTC
Permalink
Post by Dave Angel
Post by Jim Mooney Py3.4.3winXP
Post by Jim Mooney Py3.4.3winXP
K += 10
return 'the ID is', id(K), K
Ah, thanks. I forgot small integers are saved in a table. I was looking at
a demo that pointers to defaults in function parameters are persistent.
Python doesn't have pointers, and nothing here is persistent.
Persistence refers to a value surviving multiple invocations of a program.
I think the term you're looking for is "static lifetime". That object
will exist for the life of the program. The local variable name K is
bound to that object each time the function is called without an argument.
Post by Dave Angel
Post by Jim Mooney Py3.4.3winXP
It
used lists so I tried ints. Although I realized persistence also works for
dicts ;')
K[newitem] = newitem + 'item'
return 'the ID is', id(K), K
Post by Jim Mooney Py3.4.3winXP
testid('bonk')
('the ID is', 18263656, {'bonk': 'bonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('clonk')
('the ID is', 18263656, {'bonk': 'bonkitem', 'clonk': 'clonkitem'})
Post by Jim Mooney Py3.4.3winXP
testid('spam')
'spamitem'})
The object is not immutable, so it can change. Therefore the += does an
in-place change, and you keep the same id.
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Jim Mooney Py3.4.3winXP
2015-05-08 18:10:18 UTC
Permalink
Post by Dave Angel
Python doesn't have pointers
So what is the difference between a python name and a pointer? I'm a bit
fuzzy on that.
--
Jim

"What a rotten, failed experiment. I'll start over. Maybe dogs instead of
monkeys this time." --God
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-08 20:21:39 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
Post by Dave Angel
Python doesn't have pointers
So what is the difference between a python name and a pointer? I'm a bit
fuzzy on that.
What's the difference between a painting of Obama and a living state
Senator from New York?

Pointers are not part of Python. Python is a language specification.
Some implementations may use pointers to implement the binding, but
that's irrelevant unless you're doing something like linking C code to
such an implementation. Some implementations may run on Motorola
processors, but that's not part of the language either. Other
implementation do not use pointers for the binding.

A name can be reached from a namespace, and it in turn is bound to an
object. That binding is a one-way connection that lets the interpreter
find the object, given the namespace and the name.
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-05-08 22:26:16 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
Post by Dave Angel
Python doesn't have pointers
So what is the difference between a python name and a pointer?
OK, This could get deepo.
Lets start with the supoerficial...

A pointer (in most languiages) is a named alias for a memory address.
That is a name that is a specidic memory location. At least in C and
some other languages.

That means you can, in C , declare a variable (say p) to be a pointer
to some array of objects and it is simply the memory address of the
first object in the array. The second objects address is therefore
p+sizeof(o) where 'o' is the object type of the array.

You can in fact write code like this in C (and frequently do):

int p*; // declare p to be a pointer to an integer
int ia[] = {1,2,3,4,5,6,7,8,9,0}; // an array of 10 integers
p = ia; # p holds the address in ia, ie its first element

printf("%d\n", p); // print the object, ie ia[0]
printf("%d",p+3); // print the 4th object ie ia[3]

So p is a pointer to an integer. And an array is a sequence
of integers in memory so you can access subsequent memory
locations by adding numbers to p. (The compiler multiplies
the number by the size of the type of p to get the actual
memory address.)

In other languages (eg Pascal) pointers are slightly more
abstract but not much. They are more like C++ references
than memory addresses, but the end result is much the same:
they are very tightly tied to the physical concepts of
memory versus variables.

Now in contrast...
In Python a name is a much more abstract concept and is
just a label that is attached to an object. How the label
gets attached is an entirely abstract and implementation
specific concept. In practice its usually via a dictionary
so that a variable is a name which is a key of a dictionary.
The corresponding value is an object or, (crucially) maybe
a pointer to an object. But the name is not the pointer
it's the corresponding value that (may be) a pointer.

So this Python code (compare to the C above) makes no sense:

aList = [1,2,3,4,5,6,7,8,9,0]
print aList_+ 3

aList is not a pointer to the start of a sequence of
objects in memory. aList is a key to a dictionary
that holds a reference to a list of objects. And adding
3 to a key in a dictionary is not a sensible operation.

PS.
I'm writing this at 11:30pm and I've just drunk a full
bottle of (very good!) red wine all by myself (how sad!).
If it makes no sense, my apologies, I'll review it in
the morning!!! :-(

HTH
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-08 22:54:58 UTC
Permalink
Post by Alan Gauld
Post by Jim Mooney Py3.4.3winXP
Post by Dave Angel
Python doesn't have pointers
So what is the difference between a python name and a pointer?
OK, This could get deepo.
Lets start with the supoerficial...
A pointer (in most languiages) is a named alias for a memory address.
That is a name that is a specidic memory location. At least in C and
some other languages.
That means you can, in C , declare a variable (say p) to be a pointer
to some array of objects and it is simply the memory address of the
first object in the array. The second objects address is therefore
p+sizeof(o) where 'o' is the object type of the array.
int p*; // declare p to be a pointer to an integer
int ia[] = {1,2,3,4,5,6,7,8,9,0}; // an array of 10 integers
p = ia; # p holds the address in ia, ie its first element
This is a shorthand for
p = & (ia[0])
Post by Alan Gauld
printf("%d\n", p); // print the object, ie ia[0]
print("%d\n", *p) // print the first object ia[0]
print(("%d\n", p[0]); // print the first object, ie ia[0]
Post by Alan Gauld
printf("%d",p+3); // print the 4th object ie ia[3]
printf("%d",*(p+3)); // print the 4th object ie ia[3]
printf("%d",p[3]); // print the 4th object ie ia[3]

and p[274] is a random pile of bits which might or might not happen to
be readable. Using it might read some other int, it might read a few
bytes of code, it might cause a segmentation fault.
Post by Alan Gauld
So p is a pointer to an integer. And an array is a sequence
of integers in memory so you can access subsequent memory
locations by adding numbers to p. (The compiler multiplies
the number by the size of the type of p to get the actual
memory address.)
And all this is part of the language specification. C is after all, an
overblown assembly language, and all processors are expected to emulate
the appropriate Dec machine.
Post by Alan Gauld
In other languages (eg Pascal) pointers are slightly more
abstract but not much. They are more like C++ references
they are very tightly tied to the physical concepts of
memory versus variables.
Now in contrast...
In Python a name is a much more abstract concept and is
just a label that is attached to an object. How the label
gets attached is an entirely abstract and implementation
specific concept. In practice its usually via a dictionary
so that a variable is a name which is a key of a dictionary.
The corresponding value is an object or, (crucially) maybe
a pointer to an object. But the name is not the pointer
it's the corresponding value that (may be) a pointer.
aList = [1,2,3,4,5,6,7,8,9,0]
print aList_+ 3
aList is not a pointer to the start of a sequence of
objects in memory. aList is a key to a dictionary
that holds a reference to a list of objects. And adding
3 to a key in a dictionary is not a sensible operation.
I'd maintain that this is still more than what the language guarantees.
The model I have of the language is that a name is a key in some
namespace (but not necessarily a dict). The value that's associated
with that key is an abstraction that the interpreter knows how to decode
to identify one particular object. It might be a pointer, it might be
an integer, it might be a pair of values.

The object might have a fixed location, or it might move around. As
long as at any moment that the code is running, the interpreter can find
the object, it doesn't matter.
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-07 23:48:29 UTC
Permalink
Post by Emile van Sebille
Post by Jim Mooney Py3.4.3winXP
I find this a bit confusing. Since the ID of K remains the same, so it's
the same object, why isn't it increasing each time. i.e, 20, 30, 40,. I
understand that it's immutable but doesn't that mean K is created each time
in local scope so it should have a different ID each time?
Interned int
Post by Emile van Sebille
Post by Jim Mooney Py3.4.3winXP
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
testid()
('the ID is', 7515584L, 20)
Post by Jim Mooney Py3.4.3winXP
id(20)
7515584L
Post by Jim Mooney Py3.4.3winXP
id(10+10)
7515584L
Post by Jim Mooney Py3.4.3winXP
id(19+1)
7515584L
K += 10
return 'the ID is', id(K), K
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Dave Angel
2015-05-07 23:47:54 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
I find this a bit confusing. Since the ID of K remains the same, so it's
the same object, why isn't it increasing each time. i.e, 20, 30, 40,. I
understand that it's immutable but doesn't that mean K is created each time
in local scope so it should have a different ID each time?
K += 10
return 'the ID is', id(K), K
*** Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600
32 bit (Intel)] on win32. ***
testid()
('the ID is', 505991936, 20)
testid()
('the ID is', 505991936, 20)
testid()
('the ID is', 505991936, 20)
K is certainly created new each time, but it is bound to the same
object, the one created when the function is defined.

K does not have an id(), that object does.

Since the object in this case is immutable, the += creates a new object
and binds that to K. In your particular code, you never call the id()
for the initialization object. I'd add another print, that shows the
id(K) before the +=

All of this is confused by the fact that small ints happen to be
interned by your paricular implementation. So you're getting the same
<int=20> object each time.
--
DaveA
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Steven D'Aprano
2015-05-08 02:27:52 UTC
Permalink
Post by Jim Mooney Py3.4.3winXP
I find this a bit confusing. Since the ID of K remains the same, so it's
the same object, why isn't it increasing each time. i.e, 20, 30, 40,. I
understand that it's immutable but doesn't that mean K is created each time
in local scope so it should have a different ID each time?
K += 10
return 'the ID is', id(K), K
You have two questions in there, and they are unrelated.

K does not increase each time, because you throw the result away each
time and start again.

testid() uses the default of K=10. In the body of the function, K+=10
adds 10+10 to give 20, and binds that to the local variable K. But it
doesn't change the default value, which is still 10 (ints being
immutable, it cannot be changed in place). So when you call testid() the
second time, the previous value of K is lost and it starts against with
K=10.


Here is an alternative that does behave like persistent storage from
call to call:

def testid(K=[10]):
K[0] += 10
return 'the ID is', id(K), K


Because the default value is a list, and lists are mutable, so long as
we *modify* that list, the change will be seen the next time round.


Your second question is why the id() doesn't change. There are at
least two possible reasons for that:

(1) CPython caches small ints. Because they are used so frequently,
CPython saves time at the cost of a little bit of memory by using the
same objects each time, instead of creating them from scratch each time.
The precise ints which are cached are a private implementation detail
and subject to change without notice, so don't rely on that.

(2) Python only guarantees that IDs are unique for objects which exist
at the same time. In other words, Python implementations may re-use IDs.
Some do not: Jython and IronPython don't re-use IDs, but CPython does.
So if we have a sequence of events like this:

(1) create K
(2) print id(K)
(3) garbage collect K
(4) create K again
(5) print id(K) again

it is possible that the K created in (4) gets the same ID as the one
created in (1).
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Loading...