[Python-Dev] PEP 3144 review. (original) (raw)

Andrew McNamara andrewm at object-craft.com.au
Thu Sep 17 09:15:16 CEST 2009


> As the module stands, we have a pair of address-without-mask classes > called *Address, and a pair of address-with-mask classes called > *Network. So, sometimes when you want to record an address you use > a class called Network, and that class comes with a behaviours that > make no sense in the context of a singleton network end-point (it can't > "contain" other addresses, although it's .network can).

I'm going to consistently use "address" to mean a singleton and "network" to mean a container in the following.

Ta. I think it's useful to have a common terminology.

I still don't see why an address-with-mask is useful, except that the network is deducible as {'network': address & mask, 'mask': mask}. Is there any other way you would ever use that?

It seems to me that for some purposes (implementing dig(1), for example), an IPv4Address can contain only the address (ie, a 32-bit integer) as a data attribute, and (with methods for using that attribute) that is the minimal implementation of IPv4Address. However, there are other cases (eg, routing) where it's useful to associate an address with its network, and I don't see much harm in doing so by adding a 'network' attribute to the base class IPv4Address, since addresses are hardly useful except in the context of networks. Of course that attribute is often going to be None (eg, in implementing dig(1) the remote nameserver is unlikely to tell you the netmask). However, when iterating over an IPv4Network, the iterator can automatically fill in the 'network' attribute, and that's fairly cheap.

Conceptually, you sometimes need a bare address, and other times, you need an address with an associated network (host interface configs, router configs, etc). By AddressWithMask, I really mean AddressWithEnoughInformationToDeriveNetworkWhenNeeded. Conveniently, IPv4 and IPv6 addressing allows us to derive the network from the host address combined with the netmask - in other words, we don't have to attach a real Network object to Address objects until the user tries to access it, and then we derive it from the address and mask.

While to me neither the 'network' attribute nor the iterator behavior just described seems amazing useful in the base classes, it seems to me that precisely those behaviors will be reinvented over and over again for derived classes. Furthermore they are natural enough that they won't bother people who don't need them. (That's despite at least one person (IIRC it was Antoine) firmly saying "an IPv4Address should contain exactly one 32-bit int, no more, no less", so I could be wrong.)

If you have a .network attribute on an address object, checking if an address is in the same network as another address becomes:

addr_a in addr_b.network

As the module stands, you write that as:

addr_a in addr_b

I don't think the intent is as clear with the later.

It seems to me that the only good reason for not having a 'network' attribute that contains an IPv4Network instance or None is efficiency: the space for the attribute and the overhead of filling it in the iterator. I personally can't think of an application that would care (from what I hear, Cisco has no interest in writing its routers' IP stacks in Python, amazingly enough), but in theory ...

The implementation already lazily creates most things like this.

Finally, I agree that using IPv4Network as address-with-mask is a confusing, undiscoverable abuse. In particular, I think that every time I went a week without using that idiom, I'd get nervous when I saw it again: "Are you sure that won't raise an error or silently get the lower bits masked off?! If not now, in the next version?"

Yes.

-- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/



More information about the Python-Dev mailing list