NameError says variable is not defined, but only in some places
Question: I am trying to implement a keep-alive that sends some data every 30 seconds to
keep a telnet connection open.

My code calls `reinitScore` every second. This function will sometimes call
`calculateWinner`, which sends the data through telnet via
`stelnet.send(data)`.

The problem is, when I call `stelnet.send(data)` inside any function, it
raises a `NameError: global name 'stelnet' is not defined`.

My questions is: why would `stelnet.send(data)` work in one place, and not
another?

Here is the part of my code that concerns telnet transfer and function
calling:

    
    
    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)
    

I tried to declare `stelnet` as a `global` variable at many places, but it
doesn't change anything --- I always get the "not defined" `NameError`.


Answer: In response to your updated code... The error message is _still_ correct,
because although you have defined `stelnet` at the module level, you've
defined it too late. It's definition occurs _after_ its use in the
`calculateWinner` function.

Stripping your code down to a ridiculously minimal example, you are doing
something like this:

    
    
    def calculateWinner():
        # A leap of faith...  There is no `stelnet` defined
        # in this function.
        stelnet.send(results[0])
    
    def reinitScore():
        # Indirectly depends on `stelnet` too.
        calculateWinner()
    
    # But we haven't defined `stelnet` yet...
    reinitScore() # Kaboom!
    
    # These lines will never run, because the NameError has
    # already happened.
    if __name__ == '__main__':
        stelnet = ...  # Too late.
    

`calculateWinner` depends on a name that _does not exist_ when the function is
compiled. Whether it works or crashes will depend on whether some other code
has defined `stelnet` 1) where `calculateWinner` can get at it, and 2) before
`calculateWinner` is executed.

**Suggestions**

Functions that depend on global mutable state are hard to follow, let alone
code correctly. It's not easy to tell what depends on which variables, or
what's modifying them, or when. Also, coming up with an
[MCVE](https://stackoverflow.com/help/mcve) is more trouble than it should be,
because functions that appear independent might not be.

Stuff as much of your module-level code as you can into a `main` function, and
call it (and nothing else) from the body of `if __name__ == '__main__':`
(since even _that_ is actually at module level).

Consider something like this:

    
    
    def reinit_score(output_socket, shared_scores):
        # Ensuring safe concurrent access to the `shared_scores`
        # dictionary is left as an exercise for the reader.
        winner = ...  # Determined from `shared_scores`.
        output_socket.send(winner)
        for key in shared_scores:
            shared_scores[key] = 0
        threading.Timer(
          interval=1,
          function=reinit_score,
          args=[output_socket, shared_scores],
          ).start()
    
    def main():
        output_socket = ...  # This was `stelnet`.
        shared_scores = {...}  # A dictionary with 4 keys: L/R/U/D.
        reinit_score(output_socket, shared_scores)
        while True:
            play_game(shared_scores)
            # `play_game` mutates the `shared_scores` dictionary...
    
    if __name__ == '__main__':
        main()
    

These functions are still connected by the shared dictionary that they pass
around, but only functions that are explicitly passed that dictionary can
change its contents.

