This is an old revision of the document!
Start REPL (Read Execute Print Repeat) interactive mode and exit:
shell$ python # OR python3 >>> >>> quit() # OR CTRL-D shell$
Execute files:
shell$ python filename.py shell$ python filename.py arg1 arg2 arg3 shell$ python -i filename.py # start in interactive mode
Variables:
a = 10 # int b = 10.2 # float c = "Ana are mere" # str
Strings:
s1 = "Ana are mere" s2 = """This is a multiline string""" age = 20 s3 = "
Functions:
def my_function(a, b): return a + b
In Python we don't use curly braces. Instead, we use indentation to define the scope of a function/statement.
Standard I/O
input_text = input() # type str print(input_text) a = input() # 10 a = int(a) # convert to int print(a + 5) # 15
Files
f = open("path/to/file.txt") # default behaviour is 'read text' data = f.read() # reads the entire file in a string lines = f.readlines() # reads the lines in a list f.close() # when using the 'with' statement no need to close the file # 'w' - write, 'r' - read, 'a' - append, 'x' - create # 't' - text, 'b' - binary with open("result.txt", 'w') as f: # 'write text' f.write(data) f.writelines(lines)
a = 7 // 2 # a = 3 (Integer Division) b = 7 % 2 # b = 1 (Modulus) c = 2 ** 3 # c = 8 (Exponent) d = 1 ^ 0 # d = 1 (XOR operation)
i = 0 cnt = 0 while i < 100: if i == 25: continue if i < 50: cnt += 1 if i % 2 == 0: cnt *= 2 elif i >= 50 and cnt % 2 == 0: cnt += 3 else: cnt += 2 if i > 90 or cnt > 200: break
Lists:
l1 = [1, 2, 3] l1.append(4) # [1, 2, 3, 4] l1.reverse() # [4, 3, 2, 1] e1 = l1.pop() # l1 = [4, 3, 2] e1 = 1 e2 = l1.pop(0) # l1 = [3, 2], e2 = 4
class
During the labs you will often need to convert data from one format to another. The most used data formats are the following:
Finally, here you have some conversion and XOR related functions for different data formats:
import base64 # CONVERSION FUNCTIONS def _chunks(string, chunk_size): for i in range(0, len(string), chunk_size): yield string[i:i+chunk_size] def hex_2_bin(data): return ''.join(f'{int(x, 16):08b}' for x in _chunks(data, 2)) def str_2_bin(data): return ''.join(f'{ord(c):08b}' for c in data) def bin_2_hex(data): return ''.join(f'{int(b, 2):02x}' for b in _chunks(data, 8)) def str_2_hex(data): return ''.join(f'{ord(c):02x}' for c in data) def bin_2_str(data): return ''.join(chr(int(b, 2)) for b in _chunks(data, 8)) def hex_2_str(data): return ''.join(chr(int(x, 16)) for x in _chunks(data, 2)) # XOR FUNCTIONS def strxor(a, b): # xor two strings, trims the longer input return ''.join(chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)) def bitxor(a, b): # xor two bit-strings, trims the longer input return ''.join(str(int(x) ^ int(y)) for (x, y) in zip(a, b)) def hexxor(a, b): # xor two hex-strings, trims the longer input return ''.join(hex(int(x, 16) ^ int(y, 16))[2:] for (x, y) in zip(_chunks(a, 2), _chunks(b, 2))) # BASE64 FUNCTIONS def b64decode(data): return bytes_to_string(base64.b64decode(string_to_bytes(data))) def b64encode(data): return bytes_to_string(base64.b64encode(string_to_bytes(data))) # PYTHON3 'BYTES' FUNCTIONS def bytes_to_string(bytes_data): return bytes_data.decode() # default utf-8 def string_to_bytes(string_data): return string_data.encode() # default utf-8
Decode the following strings:
C1 = 010101100110000101101100011010000110000101101100011011000110000100100001 C2 = 526f636b2c2050617065722c2053636973736f727321 C3 = WW91IGRvbid0IG5lZWQgYSBrZXkgdG8gZW5jb2RlIGRhdGEu
Check out the following examples:
text1 = "Ana are mere" text2 = b"Ana are mere" type(text1) # <class 'str'> type(text2) # <class 'bytes'>
Both texts store basically the same information. The difference is in how the data is internally 'encoded' into 2 different object types. During the labs we will mostly work with str types, but some external libraries may require to transform the data from the string representation to a bytes object.
Find the plaintext messages for the following ciphertexts knowing that the cipher is the XOR operation (ciphertext = plaintext XOR key) and the key is “abcdefghijkl”.
C1 = "000100010001000000001100000000110001011100000111000010100000100100011101000001010001100100000101" C2 = "02030F07100A061C060B1909"
In this first recipe we'll see how to encrypt a single letter using Caesar's cipher.
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" def caesar_enc(letter): if letter < 'A' or letter > 'Z': print("Invalid letter") return else: return alphabet[(ord(letter) - ord('A') + 3) % len(alphabet)]
Create a new file named caesar.py containing the code above. To test the code, open the interpreter and try the following:
linux$ python >>> from caesar import * >>> print alphabet >>> alphabet[0] >>> ord('A') >>> len(alphabet) >>> ord('D') - ord('A') >>> 28 % 26 >>> -1 % 26 >>> caesar_enc('D') >>> caesar_enc('Z') >>> caesar_enc('B')
Add a caesar_dec
function to caesar.py
, which decrypts a single letter encrypted using Caesar's cipher.
We'll now expand our function to take string as input. First, a little intro to Python for
loops. Some examples:
for i in [1, 2, 3]: print i
In this first example, i
iterates through the values in list [1, 2, 3]
. The code is similar to the classical C code:
for (int i = 1; i <= 3; i++) { printf("%d\n", i); }
To create lists of integers use the range
function:
for i in range(3): print i
Execute the code above in the interpreter. Using the range function with two parameters, change the above to print integers 1 through 10.
In Python, for
can iterate through multiple types of objects, including strings. Try the below:
for letter in 'ABCD': print letter
We will now use the for
instruction to expand our caesar_enc
function:
alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' def caesar_enc_string(plaintext): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter) return ciphertext
Test the above by starting a new interpreter; this time, we'll skip the from caesar import *
part by running the source file before starting interactive mode:
linux$ python -i caesar.py >>> test = 'HELLO' >>> test + 'WORLD' >>> caesar_enc_string(test)
Another way to run things, which can be very useful in general is to use a main() function and write your program script as follows:
import sys import random import string import operator alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ' def caesar_enc(letter): if letter < 'A' or letter > 'Z': print 'Invalid letter' return else: return alphabet[(ord(letter) - ord('A') + 3) % len(alphabet)] def caesar_enc_string(plaintext): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter) return ciphertext def main(): m = 'BINEATIVENIT' c = caesar_enc_string(m) print c if __name__ == "__main__": main()
Then you can simply run the program, or type the following in a terminal:
python test_caesar.py
Add the corresponding caesar_dec_string
function.
Python allows passing default values to parameters:
def foo(a, b = 3): print a, b
>>> foo(1) >>> foo(1, 2)
We can use default parameter values to expand our caesar_enc
function to take the key as an additional parameter, without breaking compatibility with our previous code.
def caesar_enc(letter, k = 3): if letter < 'A' or letter > 'Z': print 'Invalid letter' return None else: return alphabet[(ord(letter) - ord('A') + k) % len(alphabet)] def caesar_enc_string(plaintext, k = 3): ciphertext = '' for letter in plaintext: ciphertext = ciphertext + caesar_enc(letter, k) return ciphertext
To test the new functions, try the below:
linux$ python -i caesar.py >>> caesar_enc_string('HELLO') >>> caesar_enc_string('HELLO', 0) >>> caesar_enc_string('HELLO', 1)
Using default parameters, expand your shift cipher decryption functions to support arbitrary keys.