Python Forum
Question about primitive variables.
Thread Rating:
  • 2 Vote(s) - 2.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Question about primitive variables.
#11
(Apr-01-2017, 11:00 PM)snippsat Wrote:
(Apr-01-2017, 10:27 PM)Nirelg Wrote: They are both int after all, so why when I write twice 2**2 it gives me the same id yet when I do the same for 2**11 it gives them different ids?
Integers between -5 and 256 are cached in Python.
This optimization strategy makes sense because small integers pop up all over the place,
and given that each integer takes 24 bytes, it saves a lot of memory for a typical program.

So id() show memory address.
>>> help(id)
Help on built-in function id in module builtins:

id(...)
    id(object) -> integer
    
    Return the identity of an object.  This is guaranteed to be unique among
    simultaneously existing objects.  (Hint: it's the object's memory address.)

>>> id(10)
491765920
>>> id(10)
491765920
>>> id(10)
491765920
>>> id(100)
491767360
>>> id(100)
491767360
>>> id(100)
491767360
>>> # Now over 256
>>> id(1000)
58284576
>>> id(1000)
51896640

To be honest, when I am doing the same thing you do, I am getting different results...
when I use "**" my program works as it should:
print id(2**8)
print id(2**8)
print id(2**9)
print id(2**9)
Output:
44072652 44072652 44819164 44819152
Yet when i write it like this:
print id(256)
print id(256)
print id(512)
print id(512)
Output:
45252300 45252300 45998848 45998848
Even the ints above 256 have the same id.
I tried it both with larger numbers and from cmd with the same result...
any idea why it works like this?
Reply
#12
(Apr-01-2017, 08:25 PM)Nirelg Wrote: why "2**32 is 2**32" gives us output of "False"?
Generally, is should not be used to compare ints (or for equality in general) in Python. The fact that for small values it does work is a consequence of an optimization - since the lower numbers are used so much, Python caches them to avoid having duplicates. It doesn't bother for higher numbers.

If that doesn't quite make sense, the wonderful video Ofnuts provided has a lot of good background information. Batchelder is great in general as well.
Reply
#13
Just a guess. The Garbage Collector. 

Since there is no reference to the object the Reference Counter to this memory address is 0 so the Garbage Collector is invoked and you see the result. What is GC and how it works is another question.

See this: https://www.youtube.com/watch?v=F6u5rhUQ6dU

I think that the CG is called after the RC is set to 0 for an object in the memory. And if that isn't happening the GC is called periodically
"As they say in Mexico 'dosvidaniya'. That makes two vidaniyas."
https://freedns.afraid.org
Reply
#14
(Apr-02-2017, 11:48 PM)micseydel Wrote:
(Apr-01-2017, 08:25 PM)Nirelg Wrote: why "2**32 is 2**32" gives us output of "False"?
Generally, is should not be used to compare ints (or for equality in general) in Python. The fact that for small values it does work is a consequence of an optimization - since the lower numbers are used so much, Python caches them to avoid having duplicates. It doesn't bother for higher numbers.

If that doesn't quite make sense, the wonderful video Ofnuts provided has a lot of good background information. Batchelder is great in general as well.
well, that is the problem.
It should not "bother" for higher numbers, but when i write the code:
print id(1000)
print id(1000)
They both have the same id even tho they are high numbers (even tried with higher numbers).
Output:
41870080 41870080
I also wrote "print 1000 is 1000" giving me "True", so why it works the same with higher numbers even tho it shouldn't?
keep in mind that when I write "2**10 is 2**10" it will write False! yet when doing it with the numbers them self (like 1000) it gives me True.

I watched the entire video, it helped me a lot to understand how python works, but it still did not solve the question why it gave me the same id when it should not have lol.
Reply
#15
(Apr-03-2017, 01:01 AM)Nirelg Wrote: that is the problem.
It should not "bother" for higher numbers
It's not necessarily that it shouldn't, it should be ok if it does and again it is free to do that for performance reasons, but you shouldn't rely on it not doing it and you shouldn't need to rely on it doing it. Just use == for comparing ints / longs (and strings and everything else that you really aren't checking for identity with).
Reply
#16
(Apr-03-2017, 01:01 AM)Nirelg Wrote: I also wrote "print 1000 is 1000" giving me "True", so why it works the same with higher numbers even tho it shouldn't?
The only warranty is integers between -5 and 256,over 256 depend on platform and memory it run on.
If you try on repl.it which have python 2 and 3,you see difference over 256 in Python 2 and 3.
Reply
#17
There is only one guarantee that Python enforces for id(): the id() of an object will not change as long as that object exists. Nothing more, nothing less. Every other behavior you see is more or less an accident.  Smile

Here are some examples.

>>> a=100;b=100;id(a) == id(b)
True
>>> c=100;id(a) == id(c)
True
In this example, a, b, and c are all references to the same cached value of 100 that Python creates during startup. This is simple, straight-forward, and creates much confusion.


>>> a=1000;b=1000;id(a) == id(b)
True
>>> c=1000;id(a) == id(c)
False
What's happening here? Shouldn't both inputs return False. Nope. In the first input, the parser detects that the integer 1000 is created twice and decides to have both a and b refer to the same copy of 1000. This is legal since the parser knows that the instance of 1000 does not get deleted while the parser is running so it can safely refer to it twice. In the second input, the parser has no knowledge of the previous creation of 1000, so a new instance is created.

So does that mean the parser has to know the integer values that are cached? Nope. The parser extracts the string representing the number and calls an internal function PyLong_FromString() that returns a reference to an object that represents the numeric value of the string. For integers in the range -5 to 256, PyLong_FromString() will return references to the cached objects.

Okay, so now I understand. Numeric values between -5 and 256 will always point to the same internal object. Nope. Look at the following example:

>>> a=1
>>> b=int('3'*33)
>>> c=(b * b + 1) % b
>>> a == c; id(a) == id(c)
True
False
a is a reference to the cached internal value of 1. c is the result of a calculation and is a reference to a new instance of the value 1.

Does that mean all calculations result in new instances of the result? Nope. See the next example.

>>> a=1
>>> b=int('3'*3)
>>> c=(b * b + 1) % b
>>> a == c; id(a) == id(c)
True
True
In the first calculation, the value of b*b+1 is large enough to require the use of the multiple precision routines included in Python. The multiple precision routines create a new instance of Python integer object to store the remainder. Once the result is calculated, it is just returned. No check is performed to see if the result is in the range -5 to 256. In the second calculation, the value of b*b+1 is small enough to fit in a C "long" type and the calculation is done using the C "long" type. The result is converted to a Python integer using the internal function PyInt_FromLong(). PyInt_FromLong() does check if the result can refer to a cached object.

The behavior of id() and is is confusing. id() is best used as a debugging tool. is should only be used to check if an object is exactly equal to None, True, or False. Those three objects are defined (in Python 3) to be "singleton" objects: only a single instance of those objects can exist.

And here is one more confusing example where two identical objects do not compare as equal.

>>> a=float('nan')
>>> b=a
>>> a is b; a == b; (a,) == (b,)
True
False
True
nan is special floating point value that indicates the value is "not a number". It is usually generated as the result of an error. The IEEE-754/854 standards for floating point arithmetic require that a nan must compare as not equal to every other value, including itself. That rule generates the False for the second line of the output. But as a performance optimization when comparing lists and tuples, Python assumes that the same object will always be equal to itself. That optimization generates the True on the third line of output.

I hope this helps and doesn't cause too much confusion,

casevh
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Question regarding local and global variables donmerch 12 4,975 Apr-12-2020, 03:58 PM
Last Post: TomToad
  Question about naming variables in class methods sShadowSerpent 1 1,960 Mar-25-2020, 04:51 PM
Last Post: ndc85430
  Basic Pyhton for Rhino 6 question about variables SaeedSH 1 2,107 Jan-28-2020, 04:33 AM
Last Post: Larz60+
  A question about global variables Goldberg291 3 3,961 Feb-02-2017, 10:50 PM
Last Post: ichabod801

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020