Following the advice given here, I'm using the check the ipaddress
module to perform checks of type:
In [25]: IPv4Address(u'100.64.1.1') in IPv4Network(u'100.64.0.0/10')
Out[25]: True
Works fine in IPython. Yet when I turn it into a function:
import ipaddress
def isPrivateIp(ip):
ip4addressBlocks = [u'0.0.0.0/8', u'10.0.0.0/8', u'100.64.0.0/10', u'127.0.0.0/8', u'169.254.0.0/16', u'172.16.0.0/12', u'192.0.0.0/24', u'192.0.2.0/24', u'192.88.99.0/24',
u'192.168.0.0/16', u'198.18.0.0/15', u'198.51.100.0/24', u'203.0.113.0/24', u'224.0.0.0/4', u'240.0.0.0/4', u'255.255.255.255/32']
unicoded = unicode(ip)
if any(unicoded in ipaddress.IPv4Network(address) for address in ip4addressBlocks):
return True
else:
return False
print isPrivateIp(r'169.254.255.1')
I get:
File "isPrivateIP.py", line 14, in <module>
print isPrivateIp(r'169.254.255.1')
File "isPrivateIP.py", line 9, in isPrivateIp
if any(unicoded in ipaddress.IPv4Network(address) for address in ip4addressBlocks):
File "isPrivateIP.py", line 9, in <genexpr>
if any(unicoded in ipaddress.IPv4Network(address) for address in ip4addressBlocks):
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ipaddress.py", line 705, in __contains__
if self._version != other._version:
AttributeError: 'str' object has no attribute '_version'
Why so?
@Phillip's answer is correct, I just want to expand on it a bit. I think from your other questions you're crashing through a lot of programming and Python-specific ideas all at once, and some explanation might help - or at least demonstrate that it's dense code, but not magic, and give you some other terms to Google if you want to.
Objects
It's a big topic, and there is no easy tutorial introduction, so I'm not going to try and link one. But when you do
IPv4Address(u'100.64.1.1')
, it's not just testing whether the IP address is a valid address yes or no, it's taking a lot of code that deals with IP addresses, wrapping it around the address you gave, and returning the whole thing.Like Tony Stark putting on his Iron Man suit, this takes basic text and gives you a suited-up IPv4Address object with loads of enhancements tuned for working with IP addresses.
IPv4Network()
is similar, it takes your network address text and wraps it in a load of enhancements for working with IP networks.Containment
When you do
IPv4Address(u'100.64.1.1') in IPv4Network(u'100.64.0.0/10')
, it's the extra enhancement code that understands what it means for one network to be "in" another.In your question, your code is doing:
unicoded in ipaddress.IPv4Network(address)
andunicoded
at that point is still just text."word" in "sentence with some words"
is a way to test whether one string of text is in another, so your code is doing one-half of a text membership test and the other half of an IPv4Network membership test. And that mismatch causes the failure and the error you see. The IPv4Network object can't deal.(The keyword
in
calls the Python special method__contains__
behind the scenes to handle this kind of test).Comprehension
In your other question asking about a nicer way to do things in Python (great thing to ask), the code goes from this shape of a classic
for
loop shape (example fake code):to this one-line shape:
That reshaped one-line version is a list comprehension and it's a special case made for the common pattern of "doing something for every item in a list, and gathering up the results into another list". e.g.
(More specifically, without the
[
]
on the outsides, it's the same thing but now called a generator comprehension, it's a newer version which is more memory efficient).any
Then the
any()
function summarises a list down to one result. It considers a list in terms of truth values True/False, and returns True if anything in the list is True. From above:(It goes with the
all()
function which tests if everything in the list is True).So the line of code you get from combining all of these is:
But (imho) that is still ugly. Partly it writes "ipaddress" a lot, partly it's building the enhanced objects over and over again, partly the variable name "ip4addressBlocks" doesn't explain anything about their significance, and partly you redundantly test true/false and then return true/false.
So, here, I:
ipaddress.
everywheree.g.:
You check if the unicode string
ip
is in the network, whereas before you've used anIPv4Address
instance.Your test must instead be