Summary: Integers in python are full blown objects. Small numbers are stored in a central preallocated table where each entry represents one number. Setting a variable to a small integer makes it point to an entry in that table. Multiple variables may point to the same small integer objects in that table. Fooling around with the table leads to funny results.
Weird Python Integers
61–70 of 150 posts
Re: Weird Python Integers
#62Earlier quoted context omitted.
That's only the case if you specifically treat them as full-blown objects. If you treat them as primitives they stay as primitives. Note that the type of these local variables is `Integer` rather than `int`.
Although you are technically correct (the best kind of correct), it is still a shortcoming of objects (or maybe just their implementation in Java). It is just a bad idea to implement the '==' operator using comparison on addresses instead of on values and I consider languages pretty low-level that do that. In a sane language == is always a function adhering the attributes of an equivalence relation (reflexivity, symm…
Re: Weird Python Integers
#63Re: Weird Python Integers
#64I wrote a blog post about this in the past. It's really fun going through the oddities of the language like this. It caches small integers, but also literals used in the same interpreter context (I'm probably getting that last term wrong). You'll get different results if you run these in from the shell as opposed to executing a script, try it out! Here's a fun example >>> x = 256; x is 256 True >>> x = 257; x is 257…
>>> def f():
... x = 2222; y=2222
... return x is y
...
>>> f()
True
>>> f.func_code.co_consts
(None, 2222)
This last line is showing the constant pool, which is just a standard Python tuple.I believe the REPL compiles each input in a new toplevel module context, so each input gets its own constant pool.
Functions get their own constant pools, which explains the following behavior:
>>> if True:
... def f():return 2222
... def g():return 2222
...
>>> f() is g()
FalseRe: Weird Python Integers
#65Earlier quoted context omitted.
Although you are technically correct (the best kind of correct), it is still a shortcoming of objects (or maybe just their implementation in Java). It is just a bad idea to implement the '==' operator using comparison on addresses instead of on values and I consider languages pretty low-level that do that. In a sane language == is always a function adhering the attributes of an equivalence relation (reflexivity, symm…
Why is value-equality inherently more sane than identity-equality, in an object-orientated language? Value-equality takes an unbound amount of time to compute, as well.
Re: Weird Python Integers
#66Earlier quoted context omitted.
It's just like Fortran, where everything including a constant is passed by reference, so if you assign to your arguments you might corrupt your program's only copy of 7 unless the linker put it in a read-only page.
Could you be more specific? Fortran passes arguments by reference, but writing to an argument won't mess up the "program's only copy of 7". For example, the first output of the following program is 4, but the second is still 7. program main integer m,n m = 7 call corrupt(m) write (*,*) m n = 7 write (*,*) n stop end program main subroutine corrupt (a) integer a a = 4 return end
call corrupt(7)
which causes a segfault for me. I suppose if you were using a compiler/platform that didn't store constants in read only memory, this might actually work.Re: Weird Python Integers
#67Yup, 0day hunters have fun with this behavior from time to time.
Why is it interesting for "0day hunters" in particular?
Re: Weird Python Integers
#68I wrote a blog post about this in the past. It's really fun going through the oddities of the language like this. It caches small integers, but also literals used in the same interpreter context (I'm probably getting that last term wrong). You'll get different results if you run these in from the shell as opposed to executing a script, try it out! Here's a fun example >>> x = 256; x is 256 True >>> x = 257; x is 257…
The Python interpreter compiles programs into bytecode first, and the bytecode includes instructions that load a constant from the constant pool. As an example, >>> def f(): ... x = 2222; y=2222 ... return x is y ... >>> f() True >>> f.func_code.co_consts (None, 2222) This last line is showing the constant pool, which is just a standard Python tuple. I believe the REPL compiles each input in a new toplevel module con…
>>> def f():
... x = 2221+1; y=2221+1
... return x is y
>>> f()
False
>>> f.__code__.co_consts
(None, 2221, 1, 2222, 2222)
>>> dis.dis(f)
2 0 LOAD_CONST 3 (2222)
2 STORE_FAST 0 (x)
4 LOAD_CONST 4 (2222)
6 STORE_FAST 1 (y)
3 8 LOAD_FAST 0 (x)
10 LOAD_FAST 1 (y)
12 COMPARE_OP 8 (is)
14 RETURN_VALUE
Not too sure when stuff like this would be useful (it goes way beyond the 'avoid using is unless checking references` advice), but it sure is fun.Re: Weird Python Integers
#69Is there any practical reason to use "is" to compare two ints (other than demonstrating integer interning)? Should doing so produce a warning?
Re: Weird Python Integers
#70Earlier quoted context omitted.
Could you be more specific? Fortran passes arguments by reference, but writing to an argument won't mess up the "program's only copy of 7". For example, the first output of the following program is 4, but the second is still 7. program main integer m,n m = 7 call corrupt(m) write (*,*) m n = 7 write (*,*) n stop end program main subroutine corrupt (a) integer a a = 4 return end
I think he means something like call corrupt(7) which causes a segfault for me. I suppose if you were using a compiler/platform that didn't store constants in read only memory, this might actually work.
program main
integer m,n
call corrupt(7)
write (*,*), 7
stop
end program main
subroutine corrupt (a)
integer a
a = 4
return
end
to output 4. Thanks for pointing this out, 'concede_pluto. Pretty weird!