From 2430d532e240dea55f0082d1e9bf2e0f3d7505be Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Mon, 15 Apr 2019 16:01:00 +0900 Subject: [PATCH] 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`. --- Lib/ipaddress.py | 33 +++++++-------------------------- Lib/test/test_ipaddress.py | 37 ++++++++++--------------------------- 2 files changed, 17 insertions(+), 53 deletions(-) diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py index 8c9d7406c44..7a3f36f3bc0 100644 --- a/Lib/ipaddress.py +++ b/Lib/ipaddress.py @@ -597,15 +597,11 @@ class _BaseAddress(_IPAddressBase): @functools.total_ordering class _BaseNetwork(_IPAddressBase): - """A generic IP network object. This IP class contains the version independent methods which are used by networks. - """ - def __init__(self, address): - self._cache = {} def __repr__(self): return '%s(%r)' % (self.__class__.__name__, str(self)) @@ -687,22 +683,14 @@ class _BaseNetwork(_IPAddressBase): other.network_address in self or ( other.broadcast_address in self))) - @property + @functools.cached_property def broadcast_address(self): - x = self._cache.get('broadcast_address') - if x is None: - x = self._address_class(int(self.network_address) | - int(self.hostmask)) - self._cache['broadcast_address'] = x - return x + return self._address_class(int(self.network_address) | + int(self.hostmask)) - @property + @functools.cached_property def hostmask(self): - x = self._cache.get('hostmask') - if x is None: - x = self._address_class(int(self.netmask) ^ self._ALL_ONES) - self._cache['hostmask'] = x - return x + return self._address_class(int(self.netmask) ^ self._ALL_ONES) @property def with_prefixlen(self): @@ -1346,7 +1334,7 @@ class IPv4Interface(IPv4Address): def __str__(self): return '%s/%d' % (self._string_from_ip_int(self._ip), - self.network.prefixlen) + self._prefixlen) def __eq__(self, other): address_equal = IPv4Address.__eq__(self, other) @@ -1413,7 +1401,6 @@ class IPv4Network(_BaseV4, _BaseNetwork): _address_class = IPv4Address def __init__(self, address, strict=True): - """Instantiate a new IPv4 network object. Args: @@ -1447,10 +1434,7 @@ class IPv4Network(_BaseV4, _BaseNetwork): an IPv4 address. ValueError: If strict is True and a network address is not supplied. - """ - _BaseNetwork.__init__(self, address) - # Constructing from a packed address or integer if isinstance(address, (int, bytes)): addr = address @@ -2020,7 +2004,7 @@ class IPv6Interface(IPv6Address): def __str__(self): return '%s/%d' % (self._string_from_ip_int(self._ip), - self.network.prefixlen) + self._prefixlen) def __eq__(self, other): address_equal = IPv6Address.__eq__(self, other) @@ -2125,10 +2109,7 @@ class IPv6Network(_BaseV6, _BaseNetwork): an IPv6 address. ValueError: If strict was True and a network address was not supplied. - """ - _BaseNetwork.__init__(self, address) - # Constructing from a packed address or integer if isinstance(address, (int, bytes)): addr = address diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py index 82daaff4d77..15317c94463 100644 --- a/Lib/test/test_ipaddress.py +++ b/Lib/test/test_ipaddress.py @@ -961,20 +961,6 @@ class IpaddrUnitTest(unittest.TestCase): self.assertEqual(128, ipaddress._count_righthand_zero_bits(0, 128)) 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): self.assertEqual(int(self.ipv4_network.network_address), 16909056) self.assertEqual(str(self.ipv4_network.network_address), '1.2.3.0') @@ -1986,25 +1972,22 @@ class IpaddrUnitTest(unittest.TestCase): def testNetworkElementCaching(self): # V4 - make sure we're empty - self.assertNotIn('network_address', self.ipv4_network._cache) - self.assertNotIn('broadcast_address', self.ipv4_network._cache) - self.assertNotIn('hostmask', self.ipv4_network._cache) + self.assertNotIn('broadcast_address', self.ipv4_network.__dict__) + self.assertNotIn('hostmask', self.ipv4_network.__dict__) # V4 - populate and test - self.assertEqual(self.ipv4_network.network_address, - ipaddress.IPv4Address('1.2.3.0')) self.assertEqual(self.ipv4_network.broadcast_address, ipaddress.IPv4Address('1.2.3.255')) self.assertEqual(self.ipv4_network.hostmask, ipaddress.IPv4Address('0.0.0.255')) # V4 - check we're cached - self.assertIn('broadcast_address', self.ipv4_network._cache) - self.assertIn('hostmask', self.ipv4_network._cache) + self.assertIn('broadcast_address', self.ipv4_network.__dict__) + self.assertIn('hostmask', self.ipv4_network.__dict__) # V6 - make sure we're empty - self.assertNotIn('broadcast_address', self.ipv6_network._cache) - self.assertNotIn('hostmask', self.ipv6_network._cache) + self.assertNotIn('broadcast_address', self.ipv6_network.__dict__) + self.assertNotIn('hostmask', self.ipv6_network.__dict__) # V6 - populate and test self.assertEqual(self.ipv6_network.network_address, @@ -2024,10 +2007,10 @@ class IpaddrUnitTest(unittest.TestCase): ipaddress.IPv6Address('::ffff:ffff:ffff:ffff')) # V6 - check we're cached - self.assertIn('broadcast_address', self.ipv6_network._cache) - self.assertIn('hostmask', self.ipv6_network._cache) - self.assertIn('broadcast_address', self.ipv6_interface.network._cache) - self.assertIn('hostmask', self.ipv6_interface.network._cache) + self.assertIn('broadcast_address', self.ipv6_network.__dict__) + self.assertIn('hostmask', self.ipv6_network.__dict__) + self.assertIn('broadcast_address', self.ipv6_interface.network.__dict__) + self.assertIn('hostmask', self.ipv6_interface.network.__dict__) def testTeredo(self): # stolen from wikipedia