Python NameError表示未定义变量,但仅在某些地方定义

Python NameError表示未定义变量,但仅在某些地方定义,python,nameerror,scoping,Python,Nameerror,Scoping,我正在尝试实现一个keep-alive,它每30秒发送一些数据,以保持telnet连接打开 我的代码每秒调用reinitScore。此函数有时会调用calculateWinner,它通过stelnet.send(data)通过telnet发送数据 问题是,当我在任何函数中调用stelnet.send(data)时,它会引发name错误:未定义全局名称“stelnet” 我的问题是:为什么stelnet.send(data)会在一个地方工作,而不是在另一个地方 以下是我的代码中有关telnet传输

我正在尝试实现一个keep-alive,它每30秒发送一些数据,以保持telnet连接打开

我的代码每秒调用
reinitScore
。此函数有时会调用
calculateWinner
,它通过
stelnet.send(data)
通过telnet发送数据

问题是,当我在任何函数中调用
stelnet.send(data)
时,它会引发
name错误:未定义全局名称“stelnet”

我的问题是:为什么
stelnet.send(data)
会在一个地方工作,而不是在另一个地方

以下是我的代码中有关telnet传输和函数调用的部分:

import socket, select, string, sys
import string
import threading

leftKeyCounter = 0
rightKeyCounter = 0
frontKeyCounter = 0
backKeyCounter = 0

# function called by reinitScore
def calculateWinner(d):
    scores = {}
    high_score = 0
    for key, value in d.items():
        try:
            scores[value].append(key)
        except KeyError:
            scores[value] = [key]
        if value > high_score:
            high_score = value
    results = scores[high_score]
    if len(results) == 1:
        print results[0]
        stelnet.send(results[0])
        return results[0]
    else:
        print 'TIE'
        return 'TIE', results

#called once and repeat itselfs every second
def reinitScore():
    threading.Timer(1, reinitScore).start()
    #globaling for changing the content
    global leftKeyCounter
    global rightKeyCounter
    global frontKeyCounter
    global backKeyCounter
    values = {'left' : leftKeyCounter, 'right' : rightKeyCounter, 'front' : frontKeyCounter, 'back' : backKeyCounter}
    if (leftKeyCounter != 0 or rightKeyCounter != 0 or frontKeyCounter != 0 or backKeyCounter != 0):
        calculateWinner(values)
        leftKeyCounter = 0
        rightKeyCounter = 0
        frontKeyCounter = 0
        backKeyCounter = 0
        print "back to 0"

reinitScore()
if __name__ == "__main__":

    if(len(sys.argv) < 3) :


    print 'Usage : python telnet.py hostname port'
    sys.exit()

    host = sys.argv[1]
    port = int(sys.argv[2]) 
    stelnet = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    stelnet.settimeout(2)

    # connect to remote host
    try :
        stelnet.connect((host, port))
    except :
        print 'Unable to connect'
        sys.exit()

    print 'Connected to remote host'

    while True:
       // ... Some code that has nothing to do with telnet 

    while 1:
       socket_list = [sys.stdin, stelnet]

        read_sockets, write_sockets, error_sockets = select.select(socket_list , [], [])

        for sock in read_sockets:
            if sock == stelnet:
                data = sock.recv(4096)
                if not data :
                    print 'Connection closed'
                    sys.exit()
                else :
                    sys.stdout.write(data)

            else :
                msg = sys.stdin.readline()
                stelnet.send(msg)
导入套接字,选择,字符串,系统
导入字符串
导入线程
leftKeyCounter=0
rightKeyCounter=0
frontKeyCounter=0
backKeyCounter=0
#reinitScore调用的函数
def calculateWinner(d):
分数={}
高分=0
对于键,d.items()中的值:
尝试:
分数[值]。追加(键)
除KeyError外:
分数[值]=[关键点]
如果值>高分:
高分=价值
结果=分数[高分]
如果len(结果)==1:
打印结果[0]
stelnet.send(结果[0])
返回结果[0]
其他:
打印“领带”
返回“平局”,返回结果
#每秒钟重复一次
def reinitScore():
threading.Timer(1,reinitScore.start())
#用于更改内容的全局化
全局左键计数器
全局右键计数器
全局frontKeyCounter
全局backKeyCounter
值={'left':leftKeyCounter,'right':rightKeyCounter,'front':frontKeyCounter,'back':backKeyCounter}
如果(leftKeyCounter!=0或rightKeyCounter!=0或frontKeyCounter!=0或backKeyCounter!=0):
calculateWinner(值)
leftKeyCounter=0
rightKeyCounter=0
frontKeyCounter=0
backKeyCounter=0
打印“返回到0”
reinitScore()
如果名称=“\uuuuu main\uuuuuuuu”:
如果(len(sys.argv)<3):
打印“用法:python telnet.py主机名端口”
sys.exit()
主机=sys.argv[1]
port=int(sys.argv[2])
stelnet=socket.socket(socket.AF\u INET,socket.SOCK\u流)
stelnet.settimeout(2)
#连接到远程主机
尝试:
stelnet.connect((主机、端口))
除:
打印“无法连接”
sys.exit()
打印“已连接到远程主机”
尽管如此:
// ... 一些与telnet无关的代码
而1:
插座列表=[sys.stdin,stelnet]
读插槽,写插槽,错误插槽=选择。选择(插槽列表,[],[])
对于插入式读_插槽:
如果sock==stelnet:
数据=sock.recv(4096)
如果没有数据:
打印“连接已关闭”
sys.exit()
其他:
系统标准输出写入(数据)
其他:
msg=sys.stdin.readline()
stelnet.send(msg)

我试图在许多地方将
stelnet
声明为
global
变量,但它没有改变任何事情---我总是得到“未定义”
NameError
,您的代码不工作,因为您没有将
stelnet
传递给您的函数。

作为对更新代码的响应。。。错误消息仍然正确,因为尽管您在模块级别定义了
stelnet
,但定义得太晚了。它的定义在
calculateWinner
函数中使用后出现

将代码剥离到一个极其简单的示例中,您正在执行以下操作:

def calculateWinner():
#信仰的飞跃。。。没有定义“stelnet”
#在这个函数中。
stelnet.send(结果[0])
def reinitScore():
#间接依赖于'stelnet'。
calculateWinner()
#但是我们还没有定义'stelnet'。。。
reinitScore()#Kaboom!
#这些行永远不会运行,因为NameError
#已经发生了。
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
stelnet=…#太晚了。
calculateWinner
依赖于编译函数时不存在的名称。它是否工作或崩溃将取决于其他代码是否定义了
stelnet
1)在
calculateWinner
可以到达的位置,以及2)在执行
calculateWinner
之前

建议

依赖于全局可变状态的函数很难理解,更不用说正确编码了。要知道什么取决于哪些变量、什么在修改变量、什么时候修改变量并不容易。另外,提出一个函数比它应该的麻烦多,因为看起来独立的函数可能不是

将尽可能多的模块级代码填充到
main
函数中,并从
的主体调用它(而不是其他),如果uuuu name\uuuuuuu=='uuuu main\uuuuu':
(因为这实际上也是模块级的)

考虑一下这样的情况:

def reinit_分数(输出_插槽、共享_分数):
#确保“共享”分数的安全并发访问`
#这本词典留给读者作为练习。
获胜者=…#根据“共享分数”确定。
输出_socket.send(获胜者)
对于输入共享的大学分数:
共享_分数[关键点]=0
线程。计时器(
间隔=1,
函数=reinit_分数,
args=[输出\u套接字,共享\u分数],
).start()
def main():
输出_套接字=…#这是“stelnet”。
共享_分数={…}#一个有4个键的字典:L/R/U/D。
reinit_分数(输出_插座、共享_分数)
尽管如此:
玩游戏(共享分数)
#'play_game'变异了'shared_scores'字典。。。
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
这些函数仍然通过它们传递的共享字典连接,但只有显式传递给di的函数才连接