Add int.__length__ method

num = 0
def len(int):
    while int> 0:
	int =  int//10
	num =  num+1
    return num 

if we enter a len(num) it gives :

Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    len(555)
TypeError: object of type 'int' has no len()

It would be an really helpful if it adds into python.
What do you say…?

1 Like

It’s unclear to me what problem adding a __len__ to int would solve, and int isn’t a container type so it doesn’t work well with the current API

Hello, @AaronShenny, and welcome to the Python community!

An integer represents a quantity that exists independently of the format in which it is expressed. For example, an integer might usually be expressed in base 10, but could also be expressed in binary, hexadecimal, Roman numerals, or other format. The number of characters needed to represent a given quantity among those various formats may differ. Therefore, an integer does not have an intrinsic length.

If you have an integer represented by a variable, n, and it might be positive or negative, you can simply do something like this to get its number of digits in its base 10 representation:

print(len(str(abs(n))))

For other bases or representations, adjust your strategy accordingly.

That is better than making a fundamental change to Python’s int type.

7 Likes

You seem to be trying to calculate log base 10 of an integer.

import math
print('log base 10' math.log10(555))
# or the general form
print('log base 10', math.log(555, 10))
print('log base 2', math.log(555, 2))

You can round up or down as required for your use case with math.ceil and math.floor.

3 Likes

As is, yes. If we define your function (and fix the indentation), no. But there are other problems with your implementation: it gives UnboundLocalError because num = num + 1 forces num to be a local (num = 0 should be inside the function anyway so that it gets properly reset when the function is called many times); it hides the normal definition; and the logic gives the wrong answer for a 0 input (and for negative inputs, assuming you want to count the - sign).

The simplest way to solve the problem is: len(str(555)). It’s simple, it’s correct, it’s faster even for short inputs, and it’s much faster for large inputs. Sometimes people object that this is wastefully creating a temporary string, but there will be a whole bunch of temporary integer objects anyway.

The number of digits can also be realized as a base-10 logarithm, as Barry shows. It’s even faster, and scarcely even cares about the size of the input - because it doesn’t have to divide repeatedly; it can basically use the base-256 length of the number in its raw binary form, and multiply by a constant (after adjusting for the first few bits that actually make a difference to the logarithm represented as a floating-point value).

This sometimes makes people feel uneasy because of some intuition about floating-point accuracy. But I’ve yet to be shown a case where it gets the wrong result - at least for suitably large values. Negative values and 0 need to be special-cased because the (real-valued) logarithm is not well defined there, and 1 has a logarithm of 0 rather than the required 1 (regardless of base).

I don’t agree, and I don’t see why you imagine so. Aside from the fact that making a string first is easy, this simply isn’t a common task outside the world of homework and tutorials.

2 Likes

An int is treated as a fixed width container of flags when performing embedded work in C. Perform bitwise operations on integers which are the settings to processor registers for setting up peripherals, each bit of the register is a different setting.

That definitely is not a Python integer, though. If you want that sort of integer, numpy has a set of defined-width types, and Python’s own struct module can pack and unpack them. But an integer, in Python, has no defined width and will not wrap around at any point.

There are many ways you could define the “length” of a number (eg the number of bytes required to represent it in base 256, the number of digits required to represent it in base 10, the bit length - that one’s available as a method), and none of them allow for the concept of a fixed width regardless of the value.

1 Like

Sure, but a Python integer can still be thought of as something like a container of flags - it just doesn’t actually implement that interface directly. But it does have a bit_length method.

Yep. What I should have said was: Since there’s so many options, you need to choose, which is why we have “bit length” saying so explicitly in the name. So if someone wants to pitch a different definition of “length”, it would want to be another method like that, rather than being __len__, since there’s no single logical definition of the “length” of an integer.

(Also, when I said that “none of them allow for a fixed width”, what I meant was that there’s no way to say that the integer 1 is part of a 16-flag collection or a 32-flag collection; it’s always implicitly carrying an infinite number of additional zero flags.)

3 Likes

I think @Rosuav already mentioned most things regarding the multiple possible interpretations of “integer length” so I won’t rehash that, but if you want to treat integers as “flag” containers in Python you can get their length using the int.bit_length() method.

I can fix that! Ignoring behaviour of zeros and negative values, on my macOS 13.6 / Intel machine I see this:

>>> import math
>>> digit_length1 = lambda n: len(str(n))
>>> digit_length2 = lambda n: 1 + math.floor(math.log10(n))
>>> n = 10**15 - 1
>>> digit_length1(n) == digit_length2(n)
False

Your results may vary: this is using the platform libm at some level, so is system-dependent.

7 Likes

Heh. Locally when I did performance testing, I tried math.ceil rather than adding one to the math.floor result. But that’s wrong for every integer power of 10 :wink: So that’s another reason not to do things that way, I suppose. And actually it’s probably pretty easy to construct examples regardless of the implementation details. I clearly just haven’t been looking hard enough for examples :wink:

The more interesting thing to me is that math.log10 is able to work on integers beyond the range of the double type.

Like I said that if this is added it would be really helpful because as a student we face problems when we need how many digits are there in a numerical. To get that we need to run the loop and wasting time.
Check this OUT : GitHub - AaronShenny/lenpython: It returns the length of any data types

1 Like

For negative integers the returned length is zero there.

Would it be helpful for students to have such a builtin? If this existed as builtin (for instance as a function on integers called “decimal_length” similar to “bit_length”), and I was teaching your class, I would consider explicitly forbidding students from using the builtin. Not using the builtin could be considered “more helpful” since it would stimulate students to come up with their own methods and think about the problem. Right?

1 Like

The most natural definition of the length of int in CPython is the number of 15-bit or 30-bit (depending on implementation) “digits”.

2 Likes

Why do you need to know this number? If it’s “because the assignment asked for it”, then probably the point of the assignment is for you to be able to write the algorithm. For real-world programs, it’s hard to find a situation where we would actually care.

Wait, do they not use the entire memory block for each “digit” (except perhaps the most significant one which might need a sign bit)? And do they really not use 64-bit elements in 64-bit builds?

The top bit of each chunk is unused to leave room for carries so
that multi-word additions can be done in C.

Not using more than 32 bit is probably so two chunks can be
multiplied and have the result fit in a standard C data type.

2 Likes

Ah, that would also explain using 15 bits from a 16-bit type on 32-bit builds, then. (But shouldn’t it be 31 bits on 64-bit builds, then, not 30?)

You can of course define your own object with this behaviour

class SizedInt(int):
    def __len__(self):
        value = abs(self)
        length = 0
        while value>0:
            value = value//10
            length += 1
        return length

But I would not recommend it - The len in Python is defined as the number of items (Python objects) in a collection. An int is not a collection in the standard Python definition. Your object would behave in unexpected ways.