странное поведение в закрученном обратном вызове - PullRequest
2 голосов
/ 17 сентября 2011

Цель: попытаться установить TCP-соединение со списком серверов и распечатать, если соединение было успешным и запрашивается пароль, или нет

Проблема: Кажется, что оператор (to_check -= 1) в моем обратном вызове(с именем connected ) и errback (с именем failed ) никогда не выполняется, даже если операторы печати в этих функциях имеют следующий вид.

Trying Connection to 10.1.1.0 ...
...
...
Trying Connection to 10.1.1.9 ...
Successfully connected to 10.1.1.1 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.0 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.2 and was prompted for password
10 connections left to check
Successfully connected to 10.1.1.9 and was prompted for password
10 connections left to check
....{Similar output}
Successfully connected to 10.1.1.6 and was prompted for password
10 connections left to check

Количество оставшихся проверяемых соединений должно уменьшаться, но оно остается прежним.

1 Ответ

8 голосов
/ 17 сентября 2011

Это общая проблема с вашим пониманием замыканий в python; по умолчанию переменные являются локальными для самой внутренней функции, в которой они назначены. -= является неявным присваиванием, поэтому to_check становится локальной переменной для connected и failed. Таким образом, to_check в функции main никогда не изменяется. В python 3.x, nonlocal to_check в верхней части connected и failed будут делать то, что вы ожидаете. Вот пример того, как сделать то же самое, используя мутацию в 2.x:

import itertools

def main():

    ip = "10.1.1."
    port = 23
    to_check = 10
    counter = itertools.count().next
    from twisted.internet import reactor
    def connected(whathappened):
        print >>sys.stdout, "Successfully connected to %s %s" % (whathappened[0],whathappened[1])
        return counter()

    def failed(reason):
        print >>sys.stderr, "Connection to failed : %s" % reason
        return counter()

    def checked(count):
        print >>sys.stdout, "%d connections left to check" % (to_check - count,)
        if count == to_check:
            reactor.stop()

    for i in range(0,total):
        d = check_conn(ip + str(i),port)
        d.addCallbacks(connected,failed)
        d.addBoth(checked)

    reactor.run()
...