2015-06-23 60 views
1

下面給出here的建議,我使用的檢查ipaddress模塊執行類型的檢查:在IPython中的Python:ip地址AttributeError的:「海峽」對象沒有屬性

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

工作正常。然而,當我把它變成一個功能:

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' 

爲什麼會這樣?

回答

4

您檢查unicode字符串ip是否在網絡中,而在您使用IPv4Address實例之前。

您的測試必須改爲

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

@菲利普的答案是正確的,我只是想在它擴大一點。我想從你的你通過大量的編程和Python的具體思路崩潰一下子,有些解釋可能有助於其他問題 - 或者至少證明它是密集的代碼,但不魔術,並給你一些其他如果您願意,可以向Google發送條款。

對象

這是一個很大的話題,並沒有簡單的入門教程,所以我不打算嘗試和紐帶之一。但是,當你這樣做IPv4Address(u'100.64.1.1'),它不只是測試的IP地址是否是一個有效的地址是或否,它採取了大量的代碼與IP地址的交易,包裝它,你給了周圍的地址,並返回整件事

像託尼斯塔克穿上他的鋼鐵俠套裝,這需要基本的文字,並給你一個合適的IPv4地址對象與負荷的增強調整爲IP地址使用。

IPv4Network()是相似的,它需要你的網絡地址文本並把它封裝在改進的負載與IP網絡的工作。

遏制

當你做IPv4Address(u'100.64.1.1') in IPv4Network(u'100.64.0.0/10'),那就是明白這意味着什麼了一個網絡是「中」另一個額外的增強碼。

在你的問題中,你的代碼是這樣做的:unicoded in ipaddress.IPv4Network(address)unicoded在那一點上仍然只是文本。

"word" in "sentence with some words"是測試文本的一個字符串是否是另一個,所以你的代碼做一個文本成員資格測試的二分之一和IPv4Network成員測試的另一半的方式。而這種不匹配會導致失敗和你看到的錯誤。 IPv4Network對象無法處理。

in調用幕後Python special method __contains__來處理這種測試的關鍵字)。

理解

在您的其他問題問一個更好的方式做在Python的事情(偉大的事情要問),該代碼都從這種形狀的經典for環形狀(例如假的代碼):

for network in networks: 
    test if address in network: 

這一個線形狀:

[if address in network for network in networks] 

即重塑單行versio n是list comprehension,這是一種特殊情況,用於「爲列表中的每個項目做些事情,並將結果收集到另一個列表中」的常見模式。例如

>>> 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考慮列表,並且如果列表中的任何事件爲True,則返回True。從上面:

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

(它去與all()功能,測試,如果一切列表爲True)。

這樣的代碼行你結合所有這些得到的是:

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

但(恕我直言)這仍然是醜陋的。部分它寫了很多「ipaddress」,一部分是一次又一次地構建增強對象,部分變量名稱「ip4addressBlocks」沒有解釋任何有關它們的意義,部分是冗餘測試true/false,然後返回true/false 。

所以,在這裏,我:

  • 只導入兩個從模塊的名字,這樣我就可以直接使用,而無需編寫ipaddress.到處
  • 構建保留名單IPv4Network在啓動對象一旦
  • 構建IPv4Address對象一次
  • 運行測試並直接返回值,切出「if true return true else else 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') 
+0

@TessellatingHecker什麼上好編寫的,詳盡的解釋,謝謝。 – Pyderman

相關問題