In [1]:
# Review of lists
# Define a new list
list1 = [2, 3, 7, 11]
In [4]:
# access an element
list1[2]
Out[4]:
7
In [5]:
list1[2]=13
In [6]:
list1
Out[6]:
[2, 3, 13, 11]
In [7]:
# Get length of list
len(list1)
Out[7]:
4
In [8]:
list1[3]
Out[8]:
11
In [9]:
# get last elt of list
list1[len(list1)-1]
Out[9]:
11
In [10]:
# shorthand for the above (get last element)
list1[-1]
Out[10]:
11
In [11]:
# get 2nd to last
list1[-2]
Out[11]:
13
In [12]:
# Add new elt to end of list
list1.append(20)
In [13]:
list1
Out[13]:
[2, 3, 13, 11, 20]
In [18]:
# code to make a list out of fibonacci sequence:
# 1, 1, 2, 3, 5, 8, 11
# first two elts are 1, then each after is sum of previous two
fib_list = [1,1] # initial condition
for n in range(4):
    fib_list.append(fib_list[-1] + fib_list[-2])
In [19]:
fib_list
Out[19]:
[1, 1, 2, 3, 5, 8]
In [20]:
# CHALLENGE: create a list of squares 1,4,9,16,...
sq_list = []
for n in range(1,10):
    sq_list.append(n^2)
In [21]:
sq_list
Out[21]:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
In [22]:
# shorthand for the above
[n^2 for n in range(1,10)]
Out[22]:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
In [23]:
# strings, similar to a list of characters
st = "hello"
In [24]:
# can have space, numbers (also special characters)
st2 = "this is a string1231"
In [28]:
# can access individual elts
st[1]
Out[28]:
'e'
In [29]:
# this contains similar info to string above
list2 = ['h', 'e', 'l', 'l', 'o']
In [30]:
list2[0]
Out[30]:
'h'
In [31]:
# difference between "h" and h (latter is variable, but it hasn't been defined)
list2 = [h, e]
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-31-2dd2bb285111> in <module>()
----> 1 list2 = [h, e]

NameError: name 'h' is not defined
In [32]:
h = 3 
e = 7
In [33]:
list2 = [h, e]
In [34]:
list2
Out[34]:
[3, 7]
In [38]:
# Difference between 2 and '2'
n = 2
In [39]:
n+3
Out[39]:
5
In [40]:
m ='2'
In [41]:
# Can't add character '2' to number 3
m+3
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-41-028ef7937e09> in <module>()
----> 1 m+Integer(3)

/opt/sagemath-8.9/local/lib/python2.7/site-packages/sage/rings/integer.pyx in sage.rings.integer.Integer.__add__ (build/cythonized/sage/rings/integer.c:12197)()
   1790             return y
   1791 
-> 1792         return coercion_model.bin_op(left, right, operator.add)
   1793 
   1794     cpdef _add_(self, right):

/opt/sagemath-8.9/local/lib/python2.7/site-packages/sage/structure/coerce.pyx in sage.structure.coerce.CoercionModel.bin_op (build/cythonized/sage/structure/coerce.c:10896)()
   1205         # We should really include the underlying error.
   1206         # This causes so much headache.
-> 1207         raise bin_op_exception(op, x, y)
   1208 
   1209     cpdef canonical_coercion(self, x, y):

TypeError: unsupported operand parent(s) for +: '<type 'str'>' and 'Integer Ring'
In [42]:
# strings: can't change individual elts, unlike with lists
st="hello"
st[0]='s'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-42-894e0ccbf1ea> in <module>()
      1 # strings: can't change individual elts
      2 st="hello"
----> 3 st[Integer(0)]='s'

TypeError: 'str' object does not support item assignment
In [43]:
# can't append to end of string
st.append("s")
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-43-b3c8b2b28626> in <module>()
      1 # can't append to end of string
----> 2 st.append("s")

AttributeError: 'str' object has no attribute 'append'
In [44]:
st = "this is a string"
In [45]:
st
Out[45]:
'this is a string'
In [46]:
# Start of Cryptography unit
# "Keyboard" cryptosystem
alpha =      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
code_alpha = "QWERTYUIOPASDFGHJKLZXCVBNM"
In [47]:
len(alpha) #checks 
Out[47]:
26
In [48]:
len(code_alpha)
Out[48]:
26
In [51]:
alpha.find('C') # returns index of the argument
Out[51]:
2
In [55]:
# For sub_encipher, want to substitue A->Q, B->W, C-> E etc
def sub_encipher(plaintext):
    ciphertext = []
    for c in plaintext:
        # convert character to c to a number, index of c in alpha
        numc = alpha.find(c)
        # convert numc to character in code_alpha
        codedc = code_alpha[numc]
        ciphertext.append(codedc)
    return ciphertext
In [56]:
sub_encipher("ATTACKATDAWN")
Out[56]:
['Q', 'Z', 'Z', 'Q', 'E', 'A', 'Q', 'Z', 'R', 'Q', 'V', 'F']
In [57]:
# code to decipher, switch roles of alpha, code_alpha
# switch roles of ciphertext, plaintext

def sub_decipher(ciphertext):
    plaintext = []
    for c in ciphertext:
        # convert character to c to a number, index of c in alpha
        numc = code_alpha.find(c)
        # convert numc to character in code_alpha
        decodedc = alpha[numc]
        plaintext.append(decodedc)
    return plaintext
In [58]:
sub_decipher(['Q', 'Z', 'Z', 'Q', 'E', 'A', 'Q', 'Z', 'R', 'Q', 'V', 'F'])
Out[58]:
['A', 'T', 'T', 'A', 'C', 'K', 'A', 'T', 'D', 'A', 'W', 'N']
In [59]:
# convert list of characters to string (easier to read)
"".join(sub_encipher("ATTACKATDAWN"))
Out[59]:
'QZZQEAQZRQVF'
In [64]:
# shift (Caesar) cipher
# shift place in alphabet by 3 spaces (wrap around end of alphabet)
# A->D, B->E, C->F, ..., X->A, Y->B, Z->C
def shift3_cipher(plaintext):
    ciphertext = []
    for c in plaintext:
        # convert char to index in alpha
        numc = alpha.find(c)
        # shift by 3; use mod 26 to wrap around end of alphabet
        shiftnumc = (numc + 3) % 26
        # convert back to char in alpha
        codedc = alpha[shiftnumc]
        ciphertext.append(codedc)
    return ciphertext
In [65]:
shift3_cipher("ATTACKATDAWNZ")
Out[65]:
['D', 'W', 'W', 'D', 'F', 'N', 'D', 'W', 'G', 'D', 'Z', 'Q', 'C']
In [66]:
# shift (Caesar) cipher
# shift by amount given by shift parameter
def shift_cipher(plaintext, shift):
    ciphertext = []
    for c in plaintext:
        # convert char to index in alpha
        numc = alpha.find(c)
        # shift
        shiftnumc = (numc + shift) % 26
        # convert back to char in alpha
        codedc = alpha[shiftnumc]
        ciphertext.append(codedc)
    return ciphertext
In [71]:
shift_cipher("ATTACKATDAWNZ",3)
Out[71]:
['D', 'W', 'W', 'D', 'F', 'N', 'D', 'W', 'G', 'D', 'Z', 'Q', 'C']
In [70]:
(-3)% 26 # modular arithmetic
Out[70]:
23
In [73]:
# To decipher, use -shift
shift_cipher(['D', 'W', 'W', 'D', 'F', 'N', 'D', 'W', 'G', 'D', 'Z', 'Q', 'C'],-3)
Out[73]:
['A', 'T', 'T', 'A', 'C', 'K', 'A', 'T', 'D', 'A', 'W', 'N', 'Z']
In [1]:
# this cipher has weaknesses : preserves frequencies of letters
In [2]:
#"key" for shift cipher is the amount of shifting (shift)