Python: ipaddress AttributeError: 'str' object has no attribute

Python: ipaddress AttributeError: 'str' object has no attribute

按照 给出的建议,我正在使用检查 ipaddress 模块来执行类型检查:

In [25]: IPv4Address(u'100.64.1.1') in IPv4Network(u'100.64.0.0/10')
Out[25]: True

在 IPython 中工作正常。然而,当我把它变成一个函数时:

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')

我得到:

  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'

为什么会这样?

您检查 unicode 字符串 ip 是否在网络中,而在您使用 IPv4Address 实例之前。

您的测试必须改为

if any(IPv4Address(unicoded) in ipaddress.IPv4Network(address) for address \
       in ip4addressBlocks):

@Phillip 的回答是正确的,我只是想扩展一下。我认为从你的其他问题来看,你正在通过大量的编程和 Python-特定的想法同时崩溃,一些解释可能会有所帮助 - 或者至少证明它是密集的代码,但不是 magic,如果你愿意,还可以给你一些其他的条款给Google。

对象

这是一个很大的话题,没有简单的教程介绍,所以我不打算尝试 link 一个。但是当你做 IPv4Address(u'100.64.1.1') 时,它不是 只是 测试 IP 地址是否是有效地址是或否,它需要大量处理 IP 地址的代码,包装它围绕您提供的地址,return整个

就像 Tony Stark 穿上他的钢铁侠战衣一样,它采用基本文本并为您提供适合的 IPv4Address object,并针对 IP 地址进行了大量优化。

IPv4Network() 类似,它获取您的网络地址文本并将其包装在大量用于 IP 网络的增强功能中。

遏制

当您执行 IPv4Address(u'100.64.1.1') in IPv4Network(u'100.64.0.0/10') 时,它是额外的增强代码,可以理解一个网络成为另一个网络的意义 "in"。

在你的问题中,你的代码正在做:unicoded in ipaddress.IPv4Network(address)unicoded 此时仍然只是文本。

"word" in "sentence with some words" 是一种测试一个文本字符串是否是 in 的方法,因此您的代码正在进行文本成员测试的一半,而另一个一半的 IPv4Network 成员测试。这种不匹配会导致失败和您看到的错误。 IPv4Network 对象无法处理。

(关键字in在后台调用Python special method __contains__来处理这种测试)。

领悟[​​=94=]

在你的另一个问题中询问在 Python 中做事的更好方法(问得好),代码来自经典 for 循环形状的这种形状(例如假代码):

for network in networks:
    test if address in network:

到这个单线形状:

[if address in network for network in networks]

改版后的单行版是list comprehension,是"doing something for every item in a list, and gathering up the results into another list"的普通版型的特例。例如

>>> nums = [2, 4, 6, 8, 10, 12]
>>> results = [num+1 for num in nums]

>>> results
[3, 5, 7, 9, 11, 13]

>>> results = = [num > 5 for num in nums]
[False, False, True, True, True, True]

(更具体地说,没有外部的 [ ],它是同一件事,但现在称为 generator comprehension,它是一个更新的版本,内存效率更高)。

任意

然后 any() 函数将列表总结为一个结果。它根据真值 True/False 和 returns True 来考虑列表,如果列表中的 anything 为 True。从上面:

>>> results
[False, False, True, True, True, True]
>>> any(results)
True

(它与 all() 函数一起测试列表中的所有内容是否为真)。

因此,将所有这些组合在一起得到的代码行是:

if any(ipaddress.IPv4Address(unicoded) in ipaddress.IPv4Network(address) for address in ip4addressBlocks):
    print "it's reserved"

但是(恕我直言)这仍然很难看。部分它写了很多 "ipaddress",部分它一遍又一遍地构建增强对象,部分变量名称 "ip4addressBlocks" 没有解释任何关于它们的重要性,部分你冗余测试 true/false然后 return true/false.

所以,在这里,我:

  • 只导入模块中的两个名字,这样我就可以直接使用,不用到处写ipaddress.
  • 在开始时构建一次保留列表 IPv4Network 对象
  • 构建一次 IPv4Address 对象
  • 运行 测试和 return 值直接切出 "if true return true else return false"
  • 我不确定你为什么把 unicode 和原始字符串放在各处,但似乎没有必要,所以我删除了它。

例如:

from ipaddress import IPv4Address, IPv4Network

reserved_networks = [IPv4Network(x) for x in [
    '0.0.0.0/8',      '10.0.0.0/8',     '100.64.0.0/10', '127.0.0.0/8', 
    '169.254.0.0/16', '172.16.0.0/12',  '192.0.0.0/24',  '192.0.2.0/24',      
    '192.88.99.0/24', '192.168.0.0/16', '198.18.0.0/15', '198.51.100.0/24',
    '203.0.113.0/24', '224.0.0.0/4',    '240.0.0.0/4',   '255.255.255.255/32'
    ]]

def isPrivateIp(ip):
    # True if ip is in a reserved range, otherwise False
    ip = IPv4Address(ip)
    return any((ip in net) for net in reserved_networks)

print isPrivateIp('179.254.255.1')