2

Ok, so I am writing a python encryption code. The code was longer than it needed to be, so I switched part of it over to functions. As soon as I started doing this, it said that it could not find variables. To fix this, I set the variables as global. However, it still won't work, and gives me the error:

Traceback (most recent call last):
  File "C:/Users/Alex/Desktop/Encryptor.py", line 272, in <module>
    startup()
  File "C:/Users/Alex/Desktop/Encryptor.py", line 257, in startup
    encrypt()
  File "C:/Users/Alex/Desktop/Encryptor.py", line 44, in encrypt
    maincrypt(2)
  File "C:/Users/Alex/Desktop/Encryptor.py", line 12, in maincrypt
    print newtext
UnboundLocalError: local variable 'newtext' referenced before assignment

Here is my code:

letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
def maincrypt(num):
    print otext
    print textlist
    print newtextlist
    print newtext
    print times
    print i
    add = times + num
    while add > 25:
        add = add - 25
        if ord(i) >= 65 and ord(i) <= 90:
            newtext += letters[add].uppercase
        else:
            newtext += letters[add]
def encrypt():
    global otext
    global textlist
    global newtextlist
    global newtext
    global times
    global i
    otext = raw_input("Text?")
    textlist = []
    newtextlist = []
    newtext= ""
    times = 0
    for i in otext:
        textlist.append(i)
    for i in textlist:
        if i == 'a' or i == 'A':
            maincrypt(0)
        elif i == 'b' or i == 'B':
            maincrypt(1)
        elif i == 'c' or i == 'C':
            maincrypt(2)
        elif i == 'd' or i == 'D':
            maincrypt(3)
        elif i == 'e' or i == 'E':
            maincrypt(4)
        elif i == 'f' or i == 'F':
            maincrypt(5)
        elif i == 'g' or i == 'G':
            maincrypt(6)
        elif i == 'h' or i == 'H':
            maincrypt(7)
        elif i == 'i' or i == 'I':
            maincrypt(8)
        elif i == 'j' or i == 'J':
            maincrypt(9)
        elif i == 'k' or i == 'K':
            maincrypt(10)
        elif i == 'l' or i == 'L':
            maincrypt(11)
        elif i == 'm' or i == 'M':
            maincrypt(12)
        elif i == 'n' or i == 'N':
            maincrypt(13)
        elif i == 'o' or i == 'O':
            maincrypt(14)
        elif i == 'p' or i == 'P':
            maincrypt(15)
        elif i == 'q' or i == 'Q':
            maincrypt(16)
        elif i == 'r' or i == 'R':
            maincrypt(17)
        elif i == 's' or i == 'S':
            maincrypt(18)
        elif i == 't' or i == 'T':
            maincrypt(19)
        elif i == 'u' or i == 'U':
            maincrypt(20)
        elif i == 'v' or i == 'V':
            maincrypt(21)
        elif i == 'w' or i == 'W':
            maincrypt(22)
        elif i == 'x' or i == 'X':
            maincrypt(23)
        elif i == 'y' or i == 'Y':
            maincrypt(24)
        elif i == 'z' or i == 'Z':
            maincrypt(25)
        else:
            newtext += i
        times += 1
    print newtext

def decrypt():
    otext = raw_input("Text?")
    textlist = []
    newtextlist = []
    newtext= ""
    times = 0
    for i in otext:
        textlist.append(i)
    for i in textlist:
        if i == 'a' or i == 'A':
            add = 0 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'b' or i == 'B':
            add = 1 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'c' or i == 'C':
            add = 2 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'd' or i == 'D':
            add = 3 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'e' or i == 'E':
            add = 4 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'f' or i == 'F':
            add = 5 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'g' or i == 'G':
            add = 6 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'h' or i == 'H':
            add = 7 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'i' or i == 'I':
            add = 8 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'j' or i == 'J':
            add = 9 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'k' or i == 'K':
            add = 10 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'l' or i == 'L':
            add = 11 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'm' or i == 'M':
            add = 12 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'n' or i == 'N':
            add = 13 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'o' or i == 'O':
            add = 14 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'p' or i == 'P':
            add = 15 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'q' or i == 'Q':
            add = 16 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'r' or i == 'R':
            add = 17 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 's' or i == 'S':
            add = 18 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 't' or i == 'T':
            add = 19 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'u' or i == 'U':
            add = 20 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'v' or i == 'V':
            add = 21 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'w' or i == 'W':
            add = 22 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'x' or i == 'X':
            add = 23 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'y' or i == 'Y':
            add = 24 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        elif i == 'z' or i == 'Z':
            add = 25 - times
            while add < 0:
                add = add + 25
            newtext += letters[add]
        else:
            newtext += i
        times += 1
    print newtext

def startup():
    upass = raw_input("Password: ")
    if upass == "astrocrypt":
        print """Welcome!
1: Encrypt
2: Decrypt
3: Credits
4: Quit"""
        try:
            choice = input()
        except SyntaxError:
            print "Oops! That's not a valid number! Try again!"
            startup()
        except NameError:
            print "Oops! That's not a valid number! Try again!"
            startup()
        if choice == 1:
            encrypt()
            startup()
        elif choice == 2:
            decrypt()
            startup()
        elif choice == 3:
            print "Made by Alex Taber"
            startup()
        elif choice == 4:
            pass
        else:
            print "Unknown number"
            startup()
    else:
        print "Incorrect password!"
startup()
astronautlevel
  • 478
  • 4
  • 14
  • 2
    I have a suggestion. Instead of your if/elif chains, do ord(i.upper()) - ord('A'). This will give you 0 for a/A, 1 for b/B, 2 for c/C, etc. ( http://docs.python.org/2/library/functions.html#ord ) – Patashu May 11 '13 at 13:30
  • Clever piece of code, though it doesn't solve my problem. Anyways, it feels like cheating if I don't understand it =P – astronautlevel May 11 '13 at 13:34
  • Sure, I'll explain it to you - ord('A') is 65, ord('B') is 66 and so on. ord('a') is 97 - 32 higher than 65. ord('b') is 98 and so on. ( http://www.asciitable.com/index/asciifull.gif shows the ordering ) So if I subtract ord(i) to ord('A') where i is a capital character, I get what alphabet position it is. So if I subtract ord(i.upper()) to ord('A') where i is a capital or lower case character, I get what alphabet position it is. – Patashu May 11 '13 at 13:36
  • Thanks, that clears up a lot. Should I implement it like so- for i in otext: /n newtext += ord(i.upper()) - ord('A') – astronautlevel May 11 '13 at 13:38
  • As for your problem - to protect programmers from globals, globals are not considered to exist in a function until you declare they do with `global variablename`. In maincrypt you do not declare `global newtext` nor do you create a local `newtext` by assigning to it. The += operator requires the left hand to already exist - it doesn't yet, so an exception is thrown. (BTW, if you plan to reuse this program anywhere else, it is better practice to use class variables instead of globals, so 1) if someone else uses the same globals name all is OK 2) you can have two instances of the code running – Patashu May 11 '13 at 13:42
  • Thanks for that explanation. Could you post an answer for me? – astronautlevel May 11 '13 at 14:00
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/29773/discussion-between-astronautlevel-and-patashu) – astronautlevel May 11 '13 at 14:02

2 Answers2

3

First off, there are pretty strong and virtually unbreakable encryption algorithms some of which come prepackaged with python such as hmac

import hmac

def Hash_string(ref):
        cypher = hmac.new('you secret word', 'plain-text')
        return cypher.hexdigest()

Simple enough to use and much stronger. You could also use blowfish for much more advanced and secure projects, though it doesn't come with python by default but it's simple enough to setup.

Now to your code, here's how to use global variables in python

# declare variables as global
global num1
global num2
num2=22    # give initial value to num2

def foo():
   # bind variable names to the ones in global scope
   global num2
   print num2   # output: 22
   num2 = 88
   print num2   # output: 88
   global num1
   num1 = num2

def bar():
   print num1   # output: 88
   print num2   # output 88

foo()
bar()

So you need to bind newtext to the one declared as gobal

I also suggest that you rewrite encrypt to look something like this

alpha = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']

numeric = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]

def map (ch):
   chr = ch.lower()
   return numeric[alpha.index(chr)]

this creates a mapping between numbers and alphabets so you won't need a long list of elifs

Hope this helps.

EDIT you can access globals with using the global keyword, but if you want to modify them, you first need to bind to the global var before you can change them.

EDIT changed return numeric[index(chr)] to return numeric[alpha.index(chr)] sorry for the mistake :)

SamAko
  • 3,485
  • 7
  • 41
  • 77
  • NB: At my first edit, i mean you don't need to use the global keyword when accessing globals as shown in function bar, however, when you need to modify them, then you need to use global keyword – SamAko May 11 '13 at 14:29
  • i know that there is already strong & easy encryptions built in in python. I wanted to make my own encryption. Thanks for the answer! – astronautlevel May 11 '13 at 15:41
2

To protect programmers from globals, globals are not considered to exist in a function until you declare they do with global variablename. In maincrypt you do not declare global newtext nor do you create a localnewtext by assigning to it. The += operator requires the left hand to already exist - it doesn't yet, so an exception is thrown.

By the way, if you plan to reuse this program anywhere else, it is better practice to use class variables instead of globals, so 1) if someone else uses the same globals name all is OK 2) you can have two instances of the encryptor/decryptor code running and encrypting/decrypting different things, even in parallel on different threads, without clobbering each others' globals.

Also, this code: ord(i.upper()) - ord('A') will give you 0 for 'a' and 'A', 1 for 'b' and 'B', 2 for 'c' and 'C'... and so on, so you don't need such immense if/elif chains. (Why this works is because 'A', 'B', 'C' etc are contiguous in ASCII, so 'B' - 'A' is 1 and so on)

Patashu
  • 21,443
  • 3
  • 45
  • 53