How does Python manage int and long? - python

Does anybody know how Python manage internally int and long types?
Does it choose the right type dynamically?
What is the limit for an int?
I am using Python 2.6, Is is different with previous versions?
How should I understand the code below?
>>> print type(65535)
<type 'int'>
>>> print type(65536*65536)
<type 'long'>
Update:
>>> print type(0x7fffffff)
<type 'int'>
>>> print type(0x80000000)
<type 'long'>

int and long were "unified" a few versions back. Before that it was possible to overflow an int through math ops.
3.x has further advanced this by eliminating long altogether and only having int.
Python 2: sys.maxint contains the maximum value a Python int can hold.
On a 64-bit Python 2.7, the size is 24 bytes. Check with sys.getsizeof().
Python 3: sys.maxsize contains the maximum size in bytes a Python int can be.
This will be gigabytes in 32 bits, and exabytes in 64 bits.
Such a large int would have a value similar to 8 to the power of sys.maxsize.

This PEP should help.
Bottom line is that you really shouldn't have to worry about it in python versions > 2.4

Python 2 will automatically set the type based on the size of the value. A guide of max values can be found below.
The Max value of the default Int in Python 2 is 65535, anything above that will be a long
For example:
>> print type(65535)
<type 'int'>
>>> print type(65536*65536)
<type 'long'>
In Python 3 the long datatype has been removed and all integer values are handled by the Int class. The default size of Int will depend on your CPU architecture.
For example:
32 bit systems the default datatype for integers will be 'Int32'
64 bit systems the default datatype for integers will be 'Int64'
The min/max values of each type can be found below:
Int8: [-128,127]
Int16: [-32768,32767]
Int32: [-2147483648,2147483647]
Int64: [-9223372036854775808,9223372036854775807]
Int128: [-170141183460469231731687303715884105728,170141183460469231731687303715884105727]
UInt8: [0,255]
UInt16: [0,65535]
UInt32: [0,4294967295]
UInt64: [0,18446744073709551615]
UInt128: [0,340282366920938463463374607431768211455]
If the size of your Int exceeds the limits mentioned above, python will automatically change it's type and allocate more memory to handle this increase in min/max values. Where in Python 2, it would convert into 'long', it now just converts into the next size of Int.
Example: If you are using a 32 bit operating system, your max value of an Int will be 2147483647 by default. If a value of 2147483648 or more is assigned, the type will be changed to Int64.
There are different ways to check the size of the int and it's memory allocation.
Note: In Python 3, using the built-in type() method will always return <class 'int'> no matter what size Int you are using.

On my machine:
>>> print type(1<<30)
<type 'int'>
>>> print type(1<<31)
<type 'long'>
>>> print type(0x7FFFFFFF)
<type 'int'>
>>> print type(0x7FFFFFFF+1)
<type 'long'>
Python uses ints (32 bit signed integers, I don't know if they are C ints under the hood or not) for values that fit into 32 bit, but automatically switches to longs (arbitrarily large number of bits - i.e. bignums) for anything larger. I'm guessing this speeds things up for smaller values while avoiding any overflows with a seamless transition to bignums.

Interesting. On my 64-bit (i7 Ubuntu) box:
>>> print type(0x7FFFFFFF)
<type 'int'>
>>> print type(0x7FFFFFFF+1)
<type 'int'>
Guess it steps up to 64 bit ints on a larger machine.

Python 2.7.9 auto promotes numbers.
For a case where one is unsure to use int() or long().
>>> a = int("123")
>>> type(a)
<type 'int'>
>>> a = int("111111111111111111111111111111111111111111111111111")
>>> type(a)
<type 'long'>

It manages them because int and long are sibling class definitions. They have appropriate methods for +, -, *, /, etc., that will produce results of the appropriate class.
For example
>>> a=1<<30
>>> type(a)
<type 'int'>
>>> b=a*2
>>> type(b)
<type 'long'>
In this case, the class int has a __mul__ method (the one that implements *) which creates a long result when required.

From python 3.x, the unified integer libraries are even more smarter than older versions. On my (i7 Ubuntu) box I got the following,
>>> type(math.factorial(30))
<class 'int'>
For implementation details refer Include/longintrepr.h, Objects/longobject.c and Modules/mathmodule.c files. The last file is a dynamic module (compiled to an so file). The code is well commented to follow.

Just to continue to all the answers that were given here, especially #James Lanes
the size of the integer type can be expressed by this formula:
total range = (2 ^ bit system)
lower limit = -(2 ^ bit system)*0.5
upper limit = ((2 ^ bit system)*0.5) - 1

Related

map() without conversion from byte to integer

I have a bytestring, i want to process each bytes in the bytestring. One of the way to do it is to use map(), however due to this absurd problem Why do I get an int when I index bytes? accessing bytestring by index will cause it to convert to integer (and there is no way to prevent this conversion), and so map will pass each bytes as integer instead of bytes. For example consider the following code
def test_function(input):
print(type(input))
before = b'\x00\x10\x00\x00\x07\x80\x00\x03'
print("After with map")
after_with_map = list(map(test_function, before[:]))
print("After without map")
for i in range(len(before)):
test_function(before[i:i+1])
After with map will print
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
After without map will print
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
<class 'bytes'>
Is there any way to force map() to pass bytes as bytes and not as integer?
What is the goal here? The problem, if it can be called that, is that there is no byte type. That is, there is no type in Python to represent a single byte, only a collection of bytes. Probably because the smallest python values are all multiple bytes in size.
This is a difference between bytestrings and regular strings; when you map a string, you get strings of length 1, while when you map a bytestring, you get ints instead. You could probably make an argument that Python should do the same thing for strings (mapping to Unicode codepoints) for consistency, but regardless, mapping a bytes doesn't get you byteses. But since you know that, it should be easy to work around?
The least ugly solution I can come up with is an eager solution that unpacks using the struct module, for which the c code is one of the few things in Python that natively converts to/from length 1 bytes objects:
import struct
before = b'...'
# Returns tuple of len 1 bytes
before_as_len1_bytes = struct.unpack(f'{len(before)}c', before)
A few more solutions with varying levels of ugliness that I came up with first before settling on struct.unpack as the cleanest:
Decode the bytes using latin-1 (the 1-1 bytes to str encoding that directly maps each byte value to the equivalent Unicode ordinal), then map that and encode each length 1 str back to a length 1 bytes:
from operator import methodcaller # At top of file
before = b'...'
# Makes iterator of length 1 bytes objects
before_as_len1_bytes = map(methodcaller('encode', 'latin-1'), before.decode('latin-1'))
Use re.findall to quickly convert from bytes to list of length 1 bytes:
import re # At top of file
before = b'...'
# Makes list of length 1 bytes objects
before_as_len1_bytes = re.findall(rb'.', before)
Use a couple map invocations to construct slice objects then use them to index as you do manually in your loop:
# Iterator of length 1 bytes objects
before_as_len1_bytes = map(before.__getitem__, map(slice, range(len(before)), range(1, len(before) + 1)))
Use struct.iter_unpack in one of a few ways which can then be used to reconstruct bytes objects:
import struct # At top of file for both approaches
from operator import itemgetter # At top of file for second approach
# Iterator of length 1 bytes objects
before_as_len1_bytes = map(bytes, struct.iter_unpack('B', before))
# Or a similar solution that makes the bytes directly inside tuples that must be unpacked
before_as_len1_bytes = map(itemgetter(0), struct.iter_unpack('c', before))
In practice, you probably don't need to do this, and should not, but those are some of the available options.
I don't think there's any way to keep the map from seeing integers instead of bytes. But you can easily convert back to bytes when you're done.
after_with_map = bytes(map(test_function, before[:]))

Python does not convert long to int

I have a list by connection of two strings and then converting them to integer by:
for i in xrange(0, len(FromBus[1][0])):
FromBus[1][0][i] = int(str(FromBus[1][0][i]) + str(ToBus[1][0][i]))
List looks as following:
>>> FromBus[1][0][1:5]
[3724637724L, 3724837324L, 3724837707L, 3724837707L]
List is made of longs
>>> type(FromBus[1][0][1])
<type 'long'>
Due to post processing of data in different environment I am trying to convert the long type to integer type so I need to delete 'L' at the end of each variable.
However, all of the methods I have found, failed:
>>> int(FromBus[1][0][1])
3724637724L
>>> [int(i) for i in FromBus[1][0]][1:5]
[3724637724L, 3724837324L, 37248377071L, 37248377072L]
>>> map(int, FromBus[1][0][1:5])
[3724637724L, 3724837324L, 37248377071L, 37248377072L]
My question is, what is the source of the problem here? I can easily convert them to strings. But how can I still convert long to int, without doing it thorugh string method (convert long to strings deleting the last character at the end of each string and then converting it back again to integer).
Sufficient solution for me, would be also to manimulate csv writing function deleting 'L''s while writing.
The L is part of Python's representation of the value, to show you that it's a long(). The actual number is ... well, the actual number. So there isn't really a "suffix" to trim off.
int() will still return a long() if the value is too long to fit into an int() -- but you can use str() to get just the digits in a form which is convenient to put in a CSV file.
In fact, the Python csv module (unsurprisingly) already does something like this, so I am not altogether sure you need this for your stated scenario.
Basically any bit manipulation which has an implication of a value in the 32nd bit is said to be a long. 1 << 31 becomes a long. because the 1 there is positive and you moved it over. Likewise if you set the value above the 1^31 value it will become a long. If you perform an int operation on an out of range value it will stay a long. This is kinda annoying to old-school bit manipulators who know there's 32 bits to fiddle with shove these relevant 32 bits into that size of a register.
Python refuses to make your number negative if you just happen to fill the 32nd bit through any means that wasn't - or ~. So you need to peel off the 32nd bit force it negative with operations that won't trigger the long conversion.
def sign32neg(value):
if 0x80000000 <= value <= 0xFFFFFFFF:
value &= 0x7FFFFFFF
value = int(value)
value = ~value
value ^= 0x7FFFFFFF
return value
This will make longs that could be expressed as a 32 bit negative integer, be expressed as such.
Python 2.7.12 (default, Dec 4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "copyright", "credits" or "license()" for more information.
>>> x = int
>>> x
<type 'int'>
>>> x = long
>>> x
<type 'long'>
>>> print x
<type 'long'>
>>>
So :
import struct
my_val, = struct.unpack('>d', my_string_part_if shorter_than_4Bytes_fill_\x00))
Another way :
>>> import binascii
>>> print int(binascii.hexlify("test"),16)
1952805748
>>>
**#be carefull always length 4 bytes**

What is numpy method int0?

I've seen np.int0 used for converting bounding box floating point values to int in OpenCV problems.
What exactly is np.int0?
I've seen np.uint8, np.int32, etc. I can't seem to find np.int0 in any online documentation. What kind of int does this cast arguments to?
int0 is an alias for intp; this, in turn, is
Integer used for indexing (same as C ssize_t; normally either int32 or int64)
-- Numpy docs: basic types
It's a mere alias to int64, try this from either Python 2 or Python 3:
>>> import numpy
>>> numpy.int0 is numpy.int64
True
Here is some more information:
# get complete list of datatype names
>>> np.sctypeDict.keys()
# returns the default integer type (here `int64`)
>>> np.sctypeDict['int0']
<class 'numpy.int64'>
# verify
>>> arr = np.int0([1, 2, 3])
>>> arr.nbytes
24

Long type in Python-3, NameError: name 'long' is not defined

I am new to python.And one of my requirement is to deal with long values.The problem is i didnt know how to assign a long value.This question might be very silly.But im just now starting to learn the language.I have seen a blog and i tried something like this :
# Long program in Python
x=1
y = long(x)
print(type(y))
But i am getting an error like this:
Traceback (most recent call last):
File "main.py", line 4, in <module>
y = long(x)
NameError: name 'long' is not defined
Can anyone please help me in acheiving this?
The long() function is no longer supported by Python 3 (no pun intended). It only has one built-in integral type, named int; but it behaves mostly like the old long type. So you just need to use int() built-in function in python-3.x.
Also for more information here are the complete list of changes on integer type in python-3.x:
PEP 0237: Essentially, long renamed to int. That is, there is only one built-in integral type, named int; but it behaves mostly like the old long type.
PEP 0238: An expression like 1/2 returns a float. Use 1//2 to get the truncating behavior. (The latter syntax has existed for years, at least since Python 2.2.)
The sys.maxint constant was removed, since there is no longer a limit to the value of integers. However, sys.maxsize can be used as an integer larger than any practical list or string index. It conforms to the implementation’s “natural” integer size and is typically the same as sys.maxint in previous releases on the same platform (assuming the same build options).
The repr() of a long integer doesn’t include the trailing L anymore, so code that unconditionally strips that character will chop off the last digit instead. (Use str() instead.)
Octal literals are no longer of the form 0720; use 0o720 instead.
Forget about long vs. int or about lL suffixes. Python 2.7 will promote int to long if necessary. And all integers are "long" in Python 3 (the type is renamed to int).
Assume that integers have infinite precision in Python.
To assign and print large integer in Python, just assign and print it:
x = 2**100
print(x) # -> 1267650600228229401496703205376
It works on both Python 2 and 3. The result is the same.
Python 2.7.13 it works.
x=1
y = long(x)
type(y)
<type 'long'>
you no need to define a variable as 'long' in python. Python will take care of it by default
Eg :
>>> x = 1243254675876586798
>>> type(x)
<type 'long'>
Quote from diveintopython3:
Python 2 had separate types for int and long. The int datatype was
limited by sys.maxint, which varied by platform but was usually 2^32-1.
Python 3 has just one integer type, which behaves mostly like the old
long type from Python 2. See pep 237 for details.
Python interpreter allocates memory based on the data type of variable. Therefore, by assigning different data types to variables, you can store integers, strings and longs.
>>> a = "Hello"
>>> b = 123
>>> c = 123.0
>>> d = "a"
>>> type(a)
<type 'str'>
>>> type(c)
<type 'float'>
For specific to long type, you can append "l" or "L" in the value, caps "L" is recommended. Python
displays long integers with an uppercase L
>>> e = 1234L
>>> type(e)
<type 'long'>
>>> f=1234567891223341221
>>> f
1234567891223341221L
For variable "f", while displaying the value interpreter has appended "L" with value.
As mentioned by Kasra, in Python 2.x you can typecast variable type with long(), but this is no longer supported in Python 3. This is not required as Python interpreter usually takes care if value changes, until unless you want to do it explicitly
>>> b = 1234
>>> type(b)
<type 'int'>
>>> long(b)
1234L

What does a dot after an integer mean in python?

I am looking at this line of python code (which seems to run properly):
import numpy as np
yl = 300 + 63*np.exp(-x/35.)
What is the dot doing after the 35? what does it do? Is it a signal to python that 35 is a float and not an integer? I have not seen this before. Thanks!
This is easy to test, and you're right. The dot signals a float.
$ python
>>> 1.
1.0
>>> type(1.)
<type 'float'>
Float
Next time, try to explore this using Python
r= 34.
print type(r)
Output: <type 'float'>
It tells python to treat 3 as a float(). Its just a convenient way to make a number a float for division purposes then having to explicitly call float() on it.
For example:
my_float = 3.
typed_float = float(3)
my_float == typed_float
#=> True
type(my_float)
#=> <type 'float'>
In this case you need to typecast to a float to avoid the pitfalls of integer division.

Categories