Python Forum
len() of ipaddress.ip_network()
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
len() of ipaddress.ip_network()
#6
net = ipaddress.ip_network('1::/32')
print('Number of addresses is like expected size:', net.num_addresses == 2**(128-32))
Number of usable hosts should be 2**(128-32)
The class has no method for len. Let's do one:

ipaddress.IPv6Network.__len__ = lambda self: self.num_addresses
net = ipaddress.ip_network('1::/32')
print(net.__len__())
len(net)
# BOOOM
Error:
--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) <ipython-input-52-fefbadd730e7> in <module> ----> 1 len(net) OverflowError: cannot fit 'int' into an index-sized integer
class Foo:
    def __len__(self):
        return 79228162514264337593543950336

len(Foo())
Error:
--------------------------------------------------------------------------- OverflowError Traceback (most recent call last) <ipython-input-64-955ff12672b5> in <module> ----> 1 len(Foo()) OverflowError: cannot fit 'int' into an index-sized integer
Now let's find out which number is too big:
class Foo:
    def __init__(self, len):
        self.len = len
    def __len__(self):
        return self.len

for n in itertools.count(2**63):
    try:
        len(Foo(n))
    except OverflowError:
        print('Last possible value for len is:', n-1)
        break
After some tests, I know that following does not fail:
len(Foo(2**62))

But this will fail:
len(Foo(2**63))

Doing the test above have to do 4611686018427387904 to reach from 2**62 to 2**63.
So this a little bit big for iteration, so we better calculate it and try
to make assumptions.

So let's try 2**63-1:
len(Foo(2**63-1))
Output:
9223372036854775807
From where does this number come from?

import sys
len(Foo(2**63-1)) == sys.maxsize
Output:
True
Now you can understand why they have not implemented __len__.
It's senseless to implement something, where you know from the beginning on,
that IPv6-Adresses have 128 Bit, which is a much bigger number as 2**63-1.

By the way, the iteration is still running. This approach was thought too simple :-D

I did not know this fact, that len() has an upper limit and I guess it comes from the implementation and can depend on architecture (32/64 bit).
Guessing: Maybe it comes from the limitation of addressing memory. The limit on 64 bit systems are usually 64 bit.
Some 32 bit CPUs can address more than 32 bit with PAE if they have more than 32 physical lines connected to memory for addressing.
Maybe you can look from where this limitation comes exactly and why.

The slice notation doesn't have this problem, so we are still able to address more than 2**63 in a file or iterable.
But if the object implements the __len__ method, it will fail. It will also fail, if you use this for iteration.
So if you would implement an iterator for IPv6Address, you could just make an __iter__ method and use a generator:

# definition
def my_iter(self):
    yield from self.hosts()


# monkey patching on
ipaddress.IPv6Network.__iter__ = my_iter
# monkey patching off
del my_iter # we don't need it

net = ipaddress.ip_network('1::/32')
# using directly need the iter function
# it's not an Iterator, because there is no next method
net_iter = iter(net)

# then manually do next
next(net_iter)
next(net_iter)
next(net_iter)
Let's make and IPv6Address Iterator just for fun:
def my_iter(self):
    return self

def my_next(self):
    if not hasattr(self, 'hosts_generator'):
        self.hosts_generator = self.hosts()
    return next(self.hosts_generator)
    # if StopIteration was rised by generator
    # it bubbles up to the caller
    # if the caller is a for-loop, the loop stops

# monkey patching on
ipaddress.IPv6Network.__iter__ = my_iter
ipaddress.IPv6Network.__next__ = my_next
# monkey patching off
del my_next, my_iter # we don't need it

net = ipaddress.ip_network('1::/32')
next(net)
next(net)
I think the original implementation is good as it is with paying attention about the corner cases.
Almost dead, but too lazy to die: https://sourceserver.info
All humans together. We don't need politicians!
Reply


Messages In This Thread
len() of ipaddress.ip_network() - by Skaperen - May-17-2019, 03:49 AM
RE: len() of ipaddress.ip_network() - by heiner55 - May-17-2019, 05:33 AM
RE: len() of ipaddress.ip_network() - by perfringo - May-17-2019, 06:21 AM
RE: len() of ipaddress.ip_network() - by Skaperen - May-17-2019, 07:13 PM
RE: len() of ipaddress.ip_network() - by perfringo - May-18-2019, 06:25 AM
RE: len() of ipaddress.ip_network() - by Skaperen - May-18-2019, 11:14 PM
RE: len() of ipaddress.ip_network() - by DeaD_EyE - May-18-2019, 09:58 AM
RE: len() of ipaddress.ip_network() - by Skaperen - May-19-2019, 12:25 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  module ipaddress Skaperen 2 2,463 Aug-14-2018, 05:59 AM
Last Post: Skaperen

Forum Jump:

User Panel Messages

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