bpo-27860: use cached_property (GH-12832)

* cached_property is more efficient than hand crafted cache.
* In IPv[46]Network, `self.network.prefixlen` is same to `self._prefixlen`.
This commit is contained in:
Inada Naoki 2019-04-15 16:01:00 +09:00 committed by GitHub
parent 3c5a858ec6
commit 2430d532e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 53 deletions

View File

@ -597,15 +597,11 @@ class _BaseAddress(_IPAddressBase):
@functools.total_ordering @functools.total_ordering
class _BaseNetwork(_IPAddressBase): class _BaseNetwork(_IPAddressBase):
"""A generic IP network object. """A generic IP network object.
This IP class contains the version independent methods which are This IP class contains the version independent methods which are
used by networks. used by networks.
""" """
def __init__(self, address):
self._cache = {}
def __repr__(self): def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, str(self)) return '%s(%r)' % (self.__class__.__name__, str(self))
@ -687,22 +683,14 @@ class _BaseNetwork(_IPAddressBase):
other.network_address in self or ( other.network_address in self or (
other.broadcast_address in self))) other.broadcast_address in self)))
@property @functools.cached_property
def broadcast_address(self): def broadcast_address(self):
x = self._cache.get('broadcast_address') return self._address_class(int(self.network_address) |
if x is None: int(self.hostmask))
x = self._address_class(int(self.network_address) |
int(self.hostmask))
self._cache['broadcast_address'] = x
return x
@property @functools.cached_property
def hostmask(self): def hostmask(self):
x = self._cache.get('hostmask') return self._address_class(int(self.netmask) ^ self._ALL_ONES)
if x is None:
x = self._address_class(int(self.netmask) ^ self._ALL_ONES)
self._cache['hostmask'] = x
return x
@property @property
def with_prefixlen(self): def with_prefixlen(self):
@ -1346,7 +1334,7 @@ class IPv4Interface(IPv4Address):
def __str__(self): def __str__(self):
return '%s/%d' % (self._string_from_ip_int(self._ip), return '%s/%d' % (self._string_from_ip_int(self._ip),
self.network.prefixlen) self._prefixlen)
def __eq__(self, other): def __eq__(self, other):
address_equal = IPv4Address.__eq__(self, other) address_equal = IPv4Address.__eq__(self, other)
@ -1413,7 +1401,6 @@ class IPv4Network(_BaseV4, _BaseNetwork):
_address_class = IPv4Address _address_class = IPv4Address
def __init__(self, address, strict=True): def __init__(self, address, strict=True):
"""Instantiate a new IPv4 network object. """Instantiate a new IPv4 network object.
Args: Args:
@ -1447,10 +1434,7 @@ class IPv4Network(_BaseV4, _BaseNetwork):
an IPv4 address. an IPv4 address.
ValueError: If strict is True and a network address is not ValueError: If strict is True and a network address is not
supplied. supplied.
""" """
_BaseNetwork.__init__(self, address)
# Constructing from a packed address or integer # Constructing from a packed address or integer
if isinstance(address, (int, bytes)): if isinstance(address, (int, bytes)):
addr = address addr = address
@ -2020,7 +2004,7 @@ class IPv6Interface(IPv6Address):
def __str__(self): def __str__(self):
return '%s/%d' % (self._string_from_ip_int(self._ip), return '%s/%d' % (self._string_from_ip_int(self._ip),
self.network.prefixlen) self._prefixlen)
def __eq__(self, other): def __eq__(self, other):
address_equal = IPv6Address.__eq__(self, other) address_equal = IPv6Address.__eq__(self, other)
@ -2125,10 +2109,7 @@ class IPv6Network(_BaseV6, _BaseNetwork):
an IPv6 address. an IPv6 address.
ValueError: If strict was True and a network address was not ValueError: If strict was True and a network address was not
supplied. supplied.
""" """
_BaseNetwork.__init__(self, address)
# Constructing from a packed address or integer # Constructing from a packed address or integer
if isinstance(address, (int, bytes)): if isinstance(address, (int, bytes)):
addr = address addr = address

View File

@ -961,20 +961,6 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128)) self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128))
self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network)) self.assertEqual("IPv4Network('1.2.3.0/24')", repr(self.ipv4_network))
def testMissingNetworkVersion(self):
class Broken(ipaddress._BaseNetwork):
pass
broken = Broken('127.0.0.1')
with self.assertRaisesRegex(NotImplementedError, "Broken.*version"):
broken.version
def testMissingAddressClass(self):
class Broken(ipaddress._BaseNetwork):
pass
broken = Broken('127.0.0.1')
with self.assertRaisesRegex(NotImplementedError, "Broken.*address"):
broken._address_class
def testGetNetwork(self): def testGetNetwork(self):
self.assertEqual(int(self.ipv4_network.network_address), 16909056) self.assertEqual(int(self.ipv4_network.network_address), 16909056)
self.assertEqual(str(self.ipv4_network.network_address), '1.2.3.0') self.assertEqual(str(self.ipv4_network.network_address), '1.2.3.0')
@ -1986,25 +1972,22 @@ class IpaddrUnitTest(unittest.TestCase):
def testNetworkElementCaching(self): def testNetworkElementCaching(self):
# V4 - make sure we're empty # V4 - make sure we're empty
self.assertNotIn('network_address', self.ipv4_network._cache) self.assertNotIn('broadcast_address', self.ipv4_network.__dict__)
self.assertNotIn('broadcast_address', self.ipv4_network._cache) self.assertNotIn('hostmask', self.ipv4_network.__dict__)
self.assertNotIn('hostmask', self.ipv4_network._cache)
# V4 - populate and test # V4 - populate and test
self.assertEqual(self.ipv4_network.network_address,
ipaddress.IPv4Address('1.2.3.0'))
self.assertEqual(self.ipv4_network.broadcast_address, self.assertEqual(self.ipv4_network.broadcast_address,
ipaddress.IPv4Address('1.2.3.255')) ipaddress.IPv4Address('1.2.3.255'))
self.assertEqual(self.ipv4_network.hostmask, self.assertEqual(self.ipv4_network.hostmask,
ipaddress.IPv4Address('0.0.0.255')) ipaddress.IPv4Address('0.0.0.255'))
# V4 - check we're cached # V4 - check we're cached
self.assertIn('broadcast_address', self.ipv4_network._cache) self.assertIn('broadcast_address', self.ipv4_network.__dict__)
self.assertIn('hostmask', self.ipv4_network._cache) self.assertIn('hostmask', self.ipv4_network.__dict__)
# V6 - make sure we're empty # V6 - make sure we're empty
self.assertNotIn('broadcast_address', self.ipv6_network._cache) self.assertNotIn('broadcast_address', self.ipv6_network.__dict__)
self.assertNotIn('hostmask', self.ipv6_network._cache) self.assertNotIn('hostmask', self.ipv6_network.__dict__)
# V6 - populate and test # V6 - populate and test
self.assertEqual(self.ipv6_network.network_address, self.assertEqual(self.ipv6_network.network_address,
@ -2024,10 +2007,10 @@ class IpaddrUnitTest(unittest.TestCase):
ipaddress.IPv6Address('::ffff:ffff:ffff:ffff')) ipaddress.IPv6Address('::ffff:ffff:ffff:ffff'))
# V6 - check we're cached # V6 - check we're cached
self.assertIn('broadcast_address', self.ipv6_network._cache) self.assertIn('broadcast_address', self.ipv6_network.__dict__)
self.assertIn('hostmask', self.ipv6_network._cache) self.assertIn('hostmask', self.ipv6_network.__dict__)
self.assertIn('broadcast_address', self.ipv6_interface.network._cache) self.assertIn('broadcast_address', self.ipv6_interface.network.__dict__)
self.assertIn('hostmask', self.ipv6_interface.network._cache) self.assertIn('hostmask', self.ipv6_interface.network.__dict__)
def testTeredo(self): def testTeredo(self):
# stolen from wikipedia # stolen from wikipedia