Nothing is truly "private" in Python; the saying goes that "it's cultural."  Something prefixed with a single underscore is "quasi-private" in that it's the developer's way of saying, "you shouldn't really need to touch this." (Or maybe, that if you rely on this in application code, it's subject to change with zero notice.)
The pattern the question seems to be getting at looks like this:
@property
def prefixlen(self):
    return self._prefixlen
Where:
- _prefixlenis an attribute
- prefixlenis a property - basically an instance method that you don't need to call with- (), to oversimplify things
In this case, this effectively makes prefixlen readonly, though the underlying attribute _prefixlen is perfectly modifiable if you really want to:
>>> import ipaddress
>>> nw = ipaddress.ip_network('192.0.2.0/24')
>>> nw.prefixlen
24
>>> nw.prefixlen = 32
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
If you want to modify the prefix, you might as well create a new object -- Adding a @property.setter that modifies the given object inplace would fundamentally change what you're looking at, so IPv4Network and IPv6Network instances are best treated as being immutable.
One nice trick is that the class constructors accept a tuple for the address parameter, so you can construct from parts:
>>> ipaddress.IPv4Network((nw.network_address, 32))
IPv4Network('192.0.2.0/32')
Thanks to @chepner for this last trick from his comments below.