CodeSammich
CodeSammich

Reputation: 206

Variable not Defined, Function definition includes variable?

sequence = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'


def caesar( original, variationShift):
    '''returns: a version of original created by replacing each letter with 
       the letter "variationShift" units later in the alphabet sequence.
       If variationShift is negative, replacing letter is found earlier in  
       alphabet.'''
    index = 0
    result = ''
    while index < len( original):
        lookFor = original[ index]
        foundAt = sequence.find( lookFor)
        if foundAt == -1:
            # untranslatable character
            result += lookFor
        else:
            result += sequence[ variationShift]  # negative indexes OK!

        index += 1
    return result

def encryptCaesar (original):
    caesar( original, foundAt - 3)
    return result

def decryptCaesar (original):
    caesar( original, (foundAt + 3) % len(sequence))
    return result

The variable foundAt is constantly being said to be undefined. Yet, it is defined in caesar. Is a variable undefined until the function is actually run once? Or during that run?

Upvotes: 0

Views: 1166

Answers (3)

Brad Budlong
Brad Budlong

Reputation: 1785

The other answers explain about variable scope, but you have some more basic issues. You are mixing where these variables are used. What you want to do is pass the shift. You don't know the foundAt location at the calling point, that is calculated in the loop. The other issue is the return value. You need to return the value from caesar(). The code below does the standard caesar encryption and decryption.

sequence = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

def caesar( original, variationShift):
    '''returns: a version of original created by replacing each letter with 
       the letter "variationShift" units later in the alphabet sequence.
       If variationShift is negative, replacing letter is found earlier in  
       alphabet.'''
    index = 0
    result = ''
    while index < len( original):
        lookFor = original[ index]
        foundAt = sequence.find( lookFor)
        if foundAt == -1:
            # untranslatable character
            result += lookFor
        else:
            result += sequence[ (foundAt + variationShift) % len(sequence)]
        index += 1
    return result

def encryptCaesar (original):
    return caesar( original, -3)

def decryptCaesar (original):
    return caesar( original, 3)

Upvotes: 2

A.J. Uppal
A.J. Uppal

Reputation: 19264

Due to the scope of the function, foundAt is a local variable only found within the caesar function. To get around that, use global variables:

>>> def foo():
...     global oof
...     oof = 9
... 
>>> oof
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'oof' is not defined
>>> def boo():
...     global oof
...     oof+=1
... 
>>> global oof
>>> foo()
>>> oof
9
>>> boo()
>>> oof
10
>>> 

In your code:

sequence = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'


def caesar( original, variationShift):
    global foundAt
    '''returns: a version of original created by replacing each letter with 
       the letter "variationShift" units later in the alphabet sequence.
       If variationShift is negative, replacing letter is found earlier in  
       alphabet.'''
    index = 0
    result = ''
    while index < len( original):
        lookFor = original[ index]
        foundAt = sequence.find( lookFor)
        if foundAt == -1:
            # untranslatable character
            result += lookFor
        else:
            result += sequence[ variationShift]  # negative indexes OK!

        index += 1
    return result

def encryptCaesar (original):
    global foundAt
    caesar( original, foundAt - 3)
    return result

def decryptCaesar (original):
    global foundAt
    caesar( original, (foundAt + 3) % len(sequence))
    return result

Upvotes: 0

Andrew Gorcester
Andrew Gorcester

Reputation: 19963

None of the code inside the function definition is actually run until the function is executed.

Furthermore, variables defined inside a function are only valid inside that function. To quote A Guide to Python namespaces:

At any time there are a number of scopes in operation: the scope of the current function you’re in, the scope of the module and then the scope of the Python builtins. This nesting of scopes means that one function can’t access names inside another function.

foundAt is an example of a variable defined inside a function namespace (the namespace of caesar). sequence is an example of a variable defined inside the module namespace. So, you can access sequence inside caesar and other functions, but you cannot access foundAt outside of caesar.

If you want foundAt to be accessible inside encryptCaesar you need to pass it in as an argument, or declare it in a namespace that is a parent of encryptCaesar (the module namespace -- or, alternatively, you can define encryptCaesar inside caesar and access the variable defined in the parent function via a closure). In most cases passing it in as an argument is what you wnat.

Upvotes: 0

Related Questions