大家好。最近在阅读bittorrent4.3.6的源码,有一些和列表相关的疑惑,初学python,有很多不懂,请各位高手指教。谢谢!
第一个疑惑:
以下是相关代码(ktable.py):
...
class KTable(object):
__slots__ = ('node', 'buckets')
"""local routing table for a kademlia like distributed hash table"""
def __init__(self, node):
# this is the root node, a.k.a. US!
self.node = node
self.buckets = [KBucket([], 0L, 2L**HASH_LENGTH)]
self.insertNode(node)
def _bucketIndexForInt(self, num):
"""the index of the bucket that should hold int"""
return bisect_left(self.buckets, num)
def bucketForInt(self, num):
return self.buckets[self._bucketIndexForInt(num)]
def findNodes(self, id, invalid=True):
"""
return K nodes in our own local table closest to the ID.
"""
if isinstance(id, str):
num = hash.intify(id)
elif isinstance(id, Node):
num = id.num
elif isinstance(id, int) or isinstance(id, long):
num = id
else:
raise TypeError, "findNodes requires an int, string, or Node"
nodes = []
i = self._bucketIndexForInt(num)
# if this node is already in our table then return it
try:
node = self.buckets.getNodeWithInt(num)
except ValueError:
pass
else:
return [node]
# don't have the node, get the K closest nodes
nodes = nodes + self.buckets.l
if not invalid:
nodes = [a for a in nodes if not a.invalid]
if len(nodes) < K:
# need more nodes
min = i - 1
max = i + 1
while len(nodes) < K and (min >= 0 or max < len(self.buckets)):
#ASw: note that this requires K be even
if min >= 0:
nodes = nodes + self.buckets[min].l
if max < len(self.buckets):
nodes = nodes + self.buckets[max].l
min = min - 1
max = max + 1
if not invalid:
nodes = [a for a in nodes if not a.invalid]
nodes.sort(lambda a, b, num=num: cmp(num ^ a.num, num ^ b.num))
return nodes[:K]
...
class KBucket(object):
__slots__ = ('min', 'max', 'lastAccessed', 'l', 'index', 'invalid')
def __init__(self, contents, min, max):
self.l = contents
self.index = {}
self.invalid = {}
self.min = min
self.max = max
self.lastAccessed = time()
...
红色部分就是我疑惑的地方。
_bucketIndexForInt调用的bisect_left函数,其第一个参数就是一个列表,第二个参数应该属于该列表的成员类型。
(bisect_left来自bisect模块,详情参阅
http://www.python.org/dev/doc/devel/lib/module-bisect.html)
但是,从代码可以看到,传递给bisect_left的第一个参数是KBucket类型的列表buckets,而第二个参数num,属于长整数类型。
为什么两个类型不一致呢?bisect_left似乎永远不会返回预想的值。
第二个疑惑:
def insertNode(self, node, contacted=1, nocheck=False):
"""
this insert the node, returning None if successful, returns the oldest node in the bucket if it's full
the caller responsible for pinging the returned node and calling replaceStaleNode if it is found to be stale!!
contacted means that yes, we contacted THEM and we know the node is reachable
"""
if node.id == NULL_ID or node.id == self.node.id:
return
if contacted:
node.updateLastSeen()
# get the bucket for this node
i = self._bucketIndexForInt(node.num)
# check to see if node is in the bucket already
if self.buckets.hasNode(node):
it = self.buckets.l.index(node.num)
xnode = self.buckets.l[it]
if contacted:
node.age = xnode.age
self.buckets.seenNode(node)
elif xnode.lastSeen != 0 and xnode.port == node.port and xnode.host == node.host:
xnode.updateLastSeen()
return
上面的代码中,红色部分的语句调用列表l的index方法来返回指定列表成员的索引下标值。
但是列表的index方法的参数的类型应该是列表的成员类型才对,而这里,node.num是一个长整数类型,列表的成员类型是node。这样一来,程序会抛出ValueError异常啊!怎么会这样呢?