This is a shebang (language): # -*- coding: utf-8 -*-.
# is an octothorpe or pound or hash or mesh.
Add a second line (Python version): /usr/bin/env python 2.
# -*- coding: utf-8 -*-#! /usr/bin/env python 2print"Hello World!"print"Hello Again"print"I like typing this."print"This is fun."print'Yay! Printing.'print"I'd much rather you 'not'"print'I said do not touch this.'print"testing2"
12345678
HelloWorld!HelloAgainIliketypingthis.
Thisisfun.
Yay!Printing.
I'd much rather you 'not'Isaiddonottouchthis.
testing2
print"Hens",25+30/6print"Roosters",100-25*3%4print"Now I will count the eggs:"print3+2+1-5+4%2-1/4+6# copy 3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6 straight into the shell and run it# you will get the result only (don't add print before the statement)
1234
Hens 30
Roosters 97
Now I will count the eggs:
7
print"Is it true that 3 + 2 < 5 - 7"print3+2<5-7
12
Is it true that 3 + 2 < 5 - 7
False
print"What is 3 + 2?",3+2print"What is 5 - 7?",5-7
12
What is 3 + 2? 5
What is 5 - 7? -2
print"Oh, that's why it's False."print"How about some more."
12
Oh, that's why it's False.
How about some more.
print"Is it greater?",5>-2print"Is it greater or equal?",5>=-2print"Is it less or equal?",5<=-2
123
Is it greater? True
Is it greater or equal? True
Is it less or equal? False
cars=100space_in_a_car=4.0# floatdrivers=30passengers=90cars_not_driven=cars-driverscars_driven=driverscarpool_capacity=cars_driven*space_in_a_caraverage_passengers_per_car=passengers/cars_drivenprint"There are",cars,"cars available."print"There are only",drivers,"drivers available."print"There will be",cars_not_driven,"empty cars today."print"We can transport",carpool_capacity,"people today."print"We have",passengers,"to carpool today."print"We need to put about",average_passengers_per_car,"in each cars."
123456
There are 100 cars available.
There are only 30 drivers available.
There will be 70 empty cars today.
We can transport 120.0 people today.
We have 90 to carpool today.
We need to put about 3 in each cars.
A constant variable, a variable that should never be altered, should be set in capital as PI = 3.1416.
However, if calling a ‘string’ (text, NLP), it must be done with %s; ‘numbers’ is done with %r and %d (possibly with %s).
The use and effects of the different calls is explained in Exercises 6 and 21.
my_name='Zed A. Shaw'my_age=35# not a liemy_height=74# inchesmy_weight=180# lbsmy_eyes='Blue'my_teeth='White'my_hair='Brown'print"Let's talk about %s."%my_name
1
Let's talk about Zed A. Shaw.
# does the same thingprint"He's %d years old."%my_ageprint"He's",my_age,"years old."print"He will be",my_age+1,"years old next year."
123
He's 35 years old.He's 35 years old.Hewillbe36yearsoldnextyear.
print"He's %d inches tall."%my_heightprint"He's %d pounds heavy"%my_weightprint"Actually that's not too heavy."print"He's got %s eyes and %s hair."%(my_eyes,my_hair)print"His teeth are usually %s depending on the coffee."%my_teeth
12345
He's 74 inches tall.
He's 180 pounds heavy
Actually that's not too heavy.
He's got Blue eyes and Brown hair.
His teeth are usually White depending on the coffee.
# this line is tricky, try to get it exactly rightprint"If I add %d, %d, and %d I get %d."%(my_age,my_height,my_weight,my_age+my_height+my_weight)
%r does not coerce the variable into a format (%s string or %d digit).
x="There are %d types of people."%10binary="binary"do_not="don't"y="Those who know %s and those who %s."%(binary,do_not)# assign strings or chains of strings to a variableprintxprinty
12
There are 10 types of people.
Those who know binary and those who don't.
print"I said: %r."%xprint"I also said: '%s'."%y
12
I said: 'There are 10 types of people.'.
I also said: 'Those who know binary and those who don't.'.
hilarious=Falsejoke_evaluation="Isn't that joke so funny?! %r"printjoke_evaluation%hilarious
1
Isn't that joke so funny?! False
# add two strings together, concatenate themw="This is the left side of..."e=" a string with a right side."# with Numpy, it would have added (mathematically speaking)printw+e
1
This is the left side of... a string with a right side.
Load the script in IPython with %load to study it (don’t run it!).
This type of script requires ‘external’ arguments when launched: python ex15.py test.txt
In the script itself, always preceed the ‘external’ arguments, like filename, with script since your write python ex15.py test.txt or python script argument when you launch the script.
# %load ex15.pyfromsysimportargvscript,filename=argv# similarities between# var = raw_input("string", digit, "prompt")# var = open("string")txt=open(filename)# reference to a file, not the fileprint"Here's your file %r:"%filenameprinttxt.read()print"Type the filename again:"file_again=raw_input("> ")text_again=open(file_again)print"Here's your file %r again:"%file_againprinttext_again.read()
The script again (this time, a manual import or copy-paste).
fromsysimportargv# always preceed the arguments like 'filename' with 'script'script,filename=argv# similarities# var = raw_input("string", digit, "prompt")# var = open("string")txt=open(filename)#reference to a file, not the fileprint"Here's your file %r:"%filenameprinttxt.read()print"Type the filename again:"file_again=raw_input("> ")text_again=open(file_again)print"Here's your file %r again:"%file_againprinttext_again.read()
Now, use this alternative code instead.
It does not require an external argument; the argument (filename) is in the script itself (it has become a variable).
‘Internal’ arguments are for functions (def function(arg1, arg2):); see Exercise 18.
filename="test.txt"# however, the code is limited to this file onlytxt=open(filename)# reference to a file, not the fileprint"Here's your file %r:"%filenameprinttxt.read()print"Type the filename again:"file_again=raw_input("> ")text_again=open(file_again)printtext_again.read()
'r' being the default argument, it is facultative when writing open('file', 'r').
The other arguments are mandatory; without them in open('file, 'w'), you cannot write, truncate, append or replace.
First, load the script in IPython by typing %load ex16_1.py; it then turn to a comment # %load ex16_1.py.
# %load ex16.pyfromsysimportargvscript,filename=argvprint"We're going to erase %r."%filenameprint"If you don't want that, hit CTRL-C (^C)."print"If you do want that, hit RETURN."raw_input("?")print"Opening the file..."target=open(filename,'w')print"Truncating the file!"target.truncate()print"Now, I'm going to ask you for three lines."line1=raw_input("line 1: ")line2=raw_input("line 2: ")line3=raw_input("line 3: ")print"I'm going to write these to the file."target.write(line1)# 'write' variable line1target.write("\n")# add a new linetarget.write(line2)target.write("\n")target.write(line3)target.write("\n")print"And finally, we close it."target.close()
Now, run the external file in IPython (it imports the code behind the scene).
Careful: the script requires a second argument (filename).
%runex16.pytext.txt
1 2 3 4 5 6 7 8 9101112
We're going to erase 'text.txt'.Ifyoudon't want that, hit CTRL-C (^C).Ifyoudowantthat, hitRETURN.
?
Openingthefile...
Truncatingthefile!Now, I'm going to ask you for three lines.line1: Goodmorning.
line2: Howareyou?
line3: Iwishyouagoodday.
I'm going to write these to the file.Andfinally, wecloseit.
Now, truncate (empty, delete, erase, clear) the file, reopen it, and to read it.
filename='text.txt'target=open(filename,'w')print"Truncating the file!"print"-"*25target.truncate()target.close()target=open(filename,'r')printtarget.read()target.close()
target.read(10); read the amount of bytes between the parentheses (1 byte = 1 character).
target.readline(); read one line character at a time; the first line or the file until the first \n.
target.readline(10); read 10 bytes of the first line, but never more than the first line.
readlines(); read in the whole file at once and splits it by line (create a list).
xreadlines(); read big files.
First, load script ex17_1.py in IPython. This script needs two additional arguments.
# %load ex17_1.pyfromsysimportargvfromos.pathimportexists# does the file exists, T or F?script,from_file,to_file=argvprint"Copying from %s to %s"%(from_file,to_file)in_file=open(from_file,'r')# 'r' is facultativeindata=in_file.read()# read the content, store in memoryprint"The input file is %d bytes long"%len(indata)# number of bytes in the file or length of 'indata'print"Does the output file exist? %r"%exists(to_file)# if the second file hasn't been created, this row will yield a 'False'# after you run this script, if you run it again, il will yield a 'True'print"Ready, hit RETURN to continue, CTRL-C to abort."raw_input("? ")out_file=open(to_file,'w')out_file.write(indata)print"Alright, all done."out_file.close()in_file.close()
# %load ex17_2.pyfromsysimportargvfromos.pathimportexists# does the file exists, T or F?script,from_file,to_file=argv# FIRSTin_file=open(from_file,'r')indata=in_file.read()print"The input file is %d bytes long"%len(indata)in_file.close()print"-"*25# SECONDcheckfile=open(from_file,'r')printcheckfile.readline()# read line 1, showprintcheckfile.readline()# read line 2printcheckfile.readline()# read line 3checkfile.close()print"-"*25# THIRDcheckfile2=open(from_file,'r')out_file=open(to_file,'w')indata=checkfile2.read()out_file.write(indata)print"Alright, all done."checkfile2.close()out_file.close()print"-"*25# FOURTHcheckfile3=open(to_file,'r')printcheckfile3.read()checkfile3.close()
%runex17_2.pytext2.txtnew2.txt
1 2 3 4 5 6 7 8 910111213
The input file is 49 bytes long-------------------------Good morning.How are you?I wish you a good day.-------------------------Alright, all done.-------------------------Good morning.How are you?I wish you a good day.
# indefinitedefprint_two(*args):arg1,arg2=argsprint"arg1: %r, arg2: %r"%(arg1,arg2)# two argumentsdefprint_two_again(arg1,arg2):print"arg1: %r, arg2: %r"%(arg1,arg2)# one argumentdefprint_one(arg1):print"arg1: %r"%arg1# no argumentsdefprint_none():print"I got nothin'."# indefinitedefprint_two_2(*args):print"args: %r"%(args,)# much more flexible # two argumentsdefprint_two_again_2(arg1,arg2,arg3):print"arg1: %r, arg2: %r, arg3: %r"%(arg1,arg2,arg3)# three argumentsdefprint_two_again_3(arg1,arg2,arg3):print"arg1: %r, arg2: %r, arg3: %r"%(arg1,arg2,arg3)print_two("Joe","Frank")# call a function inside a function
Give different names to functions and arguments not to get confuse.
defcheese_and_crackers(cheese_count,boxes_of_crackers):print"You have %d cheeses!"%cheese_countprint"You have %d boxes of crackers!"%boxes_of_crackersprint"Man that's enough for a party!"print"Get a blanket. \n"
print"1.We can just give the function numbers directly:"cheese_and_crackers(20,30)
print"5.Make a GUI."print"Enter the amount of cheese:",amount_of_cheese=int(raw_input())amount_of_crackers=int(raw_input("Enter the amount of crackers: "))cheese_and_crackers(amount_of_cheese,amount_of_crackers)
# %load ex20.pyfromsysimportargvscript,input_file=argv# python ex20.py test.txtdefprint_all(f):# f is the fileprintf.read()# read the file, reach the enddefrewind(f):f.seek(0)# move back to the initial position in the file# 'seek' actively move in the filedefprint_a_line(line_count,f):printline_count,f.readline()# print a line # and this line number in the filecurrent_file=open(input_file)print"First, let's print the whole file:\n"print_all(current_file)# launch function, f = current_fileprint"-"*25print"Now let's rewind, kind of like a tape."rewind(current_file)# launch function, f = current_fileprint"-"*25print"Let's print three lines:"current_line=1# load variableprint_a_line(current_line,current_file)# launch function# set 'current_line' to 1current_line=current_line+1# current_line += 1print_a_line(current_line,current_file)# 'current_line' grows to 2...# current_line = current_line + 1current_line+=1print_a_line(current_line,current_file)
%runex20.pynew2.txt
1 2 3 4 5 6 7 8 91011121314
First, let's print the whole file:
Good morning.
How are you?
I wish you a good day.
-------------------------
Now let's rewind, kind of like a tape.
-------------------------
Let's print three lines:
1 Good morning.
2 How are you?
3 I wish you a good day.
Exercise 21, Functions Can Return Something or not…¶
integer, float, int, coerce, digit, string, raw
%r for raw.
%d for digit.
%s for string.
int() with %d = integer.
int() with %r or %s = integer.
float() with %d = integer.
float() with %r or %s = float.
%r is a safer choice; see below.
a=10# a digitb=10.1print"%r"%aprint"%s"%aprint"%d"%aprint"%r"%bprint"%s"%bprint"%d"%b
123456
10101010.110.110
a="10"# a string or str(10)print"%r"%aprint"%s"%aprint"%d"%a
defadd(a,b):print"ADDING %s + %s"%(a,b)returna+bdefsubstract(a,b):print"SUBTRACTING %d - %d"%(a,b)# show the argumentsreturna-b# compute the argumentsdefmultiply(a,b):print"MULTIPLYING %d * %d"%(a,b)returna*bdefdivide(a,b):print"DIVIDING %d / %d"%(a,b)returna/b
print"Let's do some math with just functions!"aa=int(raw_input("Enter a (integer): "))# to enter an integerbb=float(raw_input("Enter b (float): "))# to enter a floatage=add(aa,bb)# launch function add()
1234
Let's do some math with just functions!Entera(integer): 1Enterb(float): 2.2ADDING1+2.2
printadd(aa,bb)
12
ADDING 1 + 2.2
3.2
height=substract(78,4)# launch function substract()weight=multiply(90,2)# launch function multiply()iq=divide(100,2)# launch function divide()printheightprintweightprintiq
# Use the variable, previously loadedprint"Age: %d, Height: %d, Weight: %d, IQ: %d"%(age,height,weight,iq)
1
Age:3,Height:74,Weight:180,IQ:50
# A puzzle for the extra credit, type it in anyway.print"Here is a puzzle."what=add(age,substract(height,multiply(weight,divide(iq,2))))# launch functions one by one!!!# Insert variable 'what' in the textprint"That becomes: ",what,"Can you do it by hand?"
print"Let's practice everything."print'You\'d need to know \'bout escapes with \\ that do \nnewlines and \ttabs.'
123
Let's practice everything.You'd need to know 'boutescapeswith \ thatdonewlinesandtabs.
poem="""\tThe lovely worldwith logic so firmly plantedconnot discern \n the needs of lovenor comprehend passion from intuitionand requires an explanation\n\t\twhere there is none."""print"----------------"printpoemprint"----------------"
1 2 3 4 5 6 7 8 9101112
----------------
The lovely world
with logic so firmly planted
connot discern
the needs of love
nor comprehend passion from intuition
and requires an explanation
where there is none.
----------------
# variable 'five'five=10-2+3-6# use of variable 'five'print"This should be five: %s"%five
1
This should be five: 5
# function with one argumentdefsecret_formula(started):jelly_beans=started*500# load variable with anotherjars=jelly_beans/1000crates=jars/100returnjelly_beans,jars,crates# variable; warning, this variable is modified further downstart_point=10000# redefine the results of a function (rename a variable)# from this point, 'jelly_beans' becomes 'beans'# and must be called so in any line of codebeans,jars,crates=secret_formula(start_point)print"With a starting point of: %d"%start_point# we apply 'bean'print"We's have %d beans, %d jars, and %d crates."%(beans,jars,crates)# modified variable is loaded into the code from this pointstart_point=start_point/10print"We can also do that this way:"# we apply the modified variable 'start_point'print"We's have %d beans, %d jars, and %d crates."%secret_formula(start_point)
1234
Withastartingpointof: 10000We's have 5000000 beans, 5000 jars, and 50 crates.Wecanalsodothatthisway:
We's have 500000 beans, 500 jars, and 5 crates.
Second, use the python engine to run pieces of codes from this file and not just trigger the whole code from this file
Check out file 25_1.txt.
# %load ex25.pydefbreak_words(stuff):"""This function will break up words for us."""words=stuff.split(' ')# the method splits the characters each time it finds a 'space'returnwords# you must specify in python where to load the result (into 'words')defsort_words(words):"""Sorts the words."""returnsorted(words)# the python function sorts the separated wordsdefprint_first_word(words):"""Prints the first word after popping in off."""word=words.pop(0)# the method returns the first word in the index (position 0)printworddefprint_last_word(words):"""Prints the last word after popping it off."""word=words.pop(-1)# the method returns the last word in the index (position -1)printworddefsort_sentence(sentence):"""Takes in a full sentence and returns the sorted words."""words=break_words(sentence)# launch a functionreturnsort_words(words)# launch another function with the result of the first functiondefprint_first_and_last(sentence):"""Prints the first and last words of the sentence."""words=break_words(sentence)print_first_word(words)print_last_word(words)defprint_first_and_last_sorted(sentence):"""Sorts the words then prints the first and last one."""words=sort_sentence(sentence)print_first_word(words)print_last_word(words)
%runex25.py
In the next script, you import the above script (ex25.py) as an external module (even though the script was previously run in IPython, and we want to simulate a script importing another script) and use its function as methods.
importex25sentence="All good things come to those who wait."words=ex25.break_words(sentence)words
the_count=[1,2,3,4,5]fruits=['apples','oranges','pears','apricots']change=[1,'pennies',2,'dimes',3,'quarters']# this first kind of for-loop goes through a listfornumberinthe_count:print"\tThis is count %d"%number
12345
This is count 1
This is count 2
This is count 3
This is count 4
This is count 5
# same as aboveforfruitinfruits:print"A fruit of type: %s"%fruit
1234
A fruit of type: apples
A fruit of type: oranges
A fruit of type: pears
A fruit of type: apricots
We can go though mixed lists too. Notice we have to use %r since we don’t know what’s in it.
foriinchange:print"\tI got %r"%i
123456
I got 1
I got 'pennies'
I got 2
I got 'dimes'
I got 3
I got 'quarters'
We can also build lists. First, start with an empty one.
elements=[]# then use the range function to do 0 to 5 counts# 0 means 1st, the 6th is excluded; 0,1,2,3,4,5foriinrange(0,6):print"Adding %d to the list."%i# append is a function that lists understandelements.append(i)# elements is a variable to which we add numbers
123456
Adding 0 to the list.
Adding 1 to the list.
Adding 2 to the list.
Adding 3 to the list.
Adding 4 to the list.
Adding 5 to the list.
We can print them out.
foriinelements:print"\tElement was: %d"%i
123456
Element was: 0
Element was: 1
Element was: 2
Element was: 3
Element was: 4
Element was: 5
print"Test the range function..."print"range(5):",range(5)print"range(6):",range(6)print"range(1, 5):",range(1,5)print"range(2, 5):",range(2,5)print"range(0, 10, 2):",range(0,10,2)
Two-dimentional lists (above 2 dimension, it can become memory-intensive to compute!).
2d, tabular, lists in list, list of lists
the_count_two=[[1,2,3],[4,5,6]]# this first kind of for-loop goes through a list# this list is not numerical, use %r or %sfornumberinthe_count_two:print"\tThis is count %r"%number
i=0numbers=[]whilei<6:print"At the top i is %d"%inumbers.append(i)i+=1print"Number now: ",numbersprint"At the botton i is %d"%iprint"The numbers: "
1 2 3 4 5 6 7 8 910111213141516171819
At the top i is 0
Number now: [0]
At the botton i is 1
At the top i is 1
Number now: [0, 1]
At the botton i is 2
At the top i is 2
Number now: [0, 1, 2]
At the botton i is 3
At the top i is 3
Number now: [0, 1, 2, 3]
At the botton i is 4
At the top i is 4
Number now: [0, 1, 2, 3, 4]
At the botton i is 5
At the top i is 5
Number now: [0, 1, 2, 3, 4, 5]
At the botton i is 6
The numbers:
fornuminnumbers:printnum
123456
012345
Make it a function.
defbreaking_list(max_of,increm):i=0numbers=[]whilei<max_of:print"At the top i is %d"%inumbers.append(i)i+=incremprint"Number now: ",numbersprint"At the botton i is %d"%iprint"The numbers: "fornuminnumbers:printnumprint"Enter an integer, a maximum, higher than 1."max_integer=int(raw_input("> "))print"Enter an integer, an increment, equal or more than 1"increment=int(raw_input("> "))print"The maximum is %d and the increment is %d"%(max_integer,increment)breaking_list(max_integer,increment)
1 2 3 4 5 6 7 8 9101112131415161718
Enter an integer, a maximum, higher than 1.
> 5
Enter an integer, an increment, equal or more than 1
> 2
The maximum is 5 and the increment is 2
At the top i is 0
Number now: [0]
At the botton i is 2
At the top i is 2
Number now: [0, 2]
At the botton i is 4
At the top i is 4
Number now: [0, 2, 4]
At the botton i is 6
The numbers:
0
2
4
Change the function, replace with a for-loops.
defbreaking_list2(max_of,increm):i=0numbers=[]foriinrange(0,max_of,increm):print"At the top i is %d"%inumbers.append(i)i+=incremprint"Number now: ",numbersprint"At the botton i is %d"%iprint"The numbers: "fornuminnumbers:printnummax_integer2=max_integer+2increment2=increment+1breaking_list2(max_integer2,increment2)
1 2 3 4 5 6 7 8 910111213
At the top i is 0
Number now: [0]
At the botton i is 3
At the top i is 3
Number now: [0, 3]
At the botton i is 6
At the top i is 6
Number now: [0, 3, 6]
At the botton i is 9
The numbers:
0
3
6
Let’s build a scenario; functions leading to other functions.
def gold_room():
def bear_room():
def cthulhu_room():
def dead(why):
def start():
start() to launch the chain reaction.
fromsysimportexitdefgold_room():print"This room is full of gold. How much do you take?"choice=raw_input("Write any number from 0 to 100> ")# variableif"0"inchoiceor"1"inchoice:# could be 0, 1, 10, 11:19, 20, 21, 30, 31, 40, 41, 50, 51, etc.how_much=int(choice)# variableelse:dead("Man, learn to type a number.")# launch function deadifhow_much<50:print"Nice, you're not greedy, you win!"exit(0)# launch system function exitelse:dead("You greedy bastard!")# launch function deaddefbear_room():print"There is bear here."print"The bear has a bunch of honey."print"The fat bear is in front of another door."print"How are you going to move the bear?"bear_moved=False# variablewhileTrue:# infinite loop, run until it finds a right answerchoice=raw_input("Write 'take honey', 'taunt bear' or 'open door'> ")# variableifchoice=="take honey":# variable checkdead("The bear looks at you then slaps your face off.")# launch function deadelifchoice=="taunt bear"andnotbear_moved:# double variables checkprint"The bear has moved from the door. You can go thought it now."bear_moved=True# change the variableelifchoice=="taunt bear"andbear_moved:dead("The bear gets pissed off and chews your leg off.")elifchoice=="open door"andbear_moved:# variable checkgold_room()# launch function gold_roomelse:print"I got no idea what that means."defcthulhu_room():print"Here you see the great evil Cthulhu."print"He, it, whatever stares at you and you go insane."print"Do you flee your life or eat your head?"choice=raw_input("Write 'flee' or 'head'> ")# variableif"flee"inchoice:# variable checkstart()# launch function startelif"head"inchoice:dead("Well that was tasty!")else:cthulhu_room()# launch functiondefdead(why):printwhy,"Good job!"exit(0)# launch system function exit# exit(0) is neutral# exit(1) is an error, could be a useful warning# exit(2) or others like exit(100) are other warnings, or different messagesdefstart():print"You are in a dark room."print"There is a door to your right and left."print"Which one do you take: left or right?"choice=raw_input("Write 'left' or 'right'> ")# variableifchoice=="left":# variable check, exactbear_room()# launch function bear_roomelifchoice=="right":# variable check, exactcthulhu_room()else:dead("You stumble around the room until you starve.")start()# launch the chain reaction
ten_things="Apples Oranges Crows Telephones Light Sugar"print"ten_things:",ten_things,", not a list"print"Wait there are not 10 things is that list. Let's fix that."
stuff=ten_things.split(' ')# variable ten_things, method splitprint"stuff:",stuff,", a list"
1
stuff: ['Apples', 'Oranges', 'Crows', 'Telephones', 'Light', 'Sugar'] , a list
more_stuff=["Day","Night","Song","Frisbee","Corn","Banana","Girl","Boy"]# list variableprint"more_stuff:",more_stuff,", a list"
1
more_stuff: ['Day', 'Night', 'Song', 'Frisbee', 'Corn', 'Banana', 'Girl', 'Boy'] , a list
Most of the time, a for-loop is better than a while-loop.
A while-loop is better when there is a test, a condition.
whilelen(stuff)!=10:next_one=more_stuff.pop()# load a variable with another variable, method pop, pop means extracting 1 item from a list variable, the last item in the listprint"Adding: ",next_one# show the contentstuff.append(next_one)# variable stuff add 1-item list variable; the loop will go as long as stuff has less than 10 items print"stuff:",stuffprint"There are %d items now."%len(stuff)# length of stuff or the number of items in itprint"There we go: ",stuff
print"Let's do some things with stuff."# print and pop choosen items according to the index# could also be random index values!!!# could reorder the list before (ascending, descending) printstuff[1]# the 2nd itemprintstuff[2]# the 3rd itemprintstuff[-1]# the last itemprintstuff[-2]printstuff.pop()# pop the last itemprintstuff.pop(0)# pop the first itemprintstuff.pop(1)# pop the 2nd itemprintstuff.pop(-1)# pop the last itemprint' '.join(stuff)# var.split(' ') vs ' '.join(var), concatenate the listprint'#'.join(stuff[3:5])# add a character at position 3 and 4 (4th, 5th, excluding the last)
1 2 3 4 5 6 7 8 91011
Let's do some things with stuff.OrangesCrowsCornBananaCornApplesCrowsBananaOrangesTelephonesLightSugarBoyGirlSugar#Boy
print"Dictionary 'cities': ",citiesprint'-'*10print"NY State has: ",cities['NY']# call the keyprint"OR State has: ",cities['OR']# get the value
1234
Dictionary 'cities': {'FL': 'Jacksonville', 'CA': 'San Francisco', 'MI': 'Detroit', 'OR': 'Portland', 'NY': 'New York'}
----------
NY State has: New York
OR State has: Portland
Print some states.
print"Dictionary 'states': ",statesprint'-'*10print"Michigan's abbreviation is: ",states['Michigan']print"Florida's abbrebiation is: ",states['Florida']
print"Enumerate Dictionary 'cities', key:value..."forabbrev,cityincities.items():print"%s has the city %s"%(abbrev,city)
123456
Enumerate Dictionary 'cities', key:value...
FL has the city Jacksonville
CA has the city San Francisco
MI has the city Detroit
OR has the city Portland
NY has the city New York
Now do both at the same time.
print"Enumerate both dictionaries..."forstate,abbrevinstates.items():print"%s state is abbreviated %s and has city %s"%(state,abbrev,cities[abbrev])# state California gives abbrev CA, inside cities gives San Francisco
I AM APPLES!
I AM APPLES!
Living reflection of a dream
Use a class instead of an imported module.
Remember: class method = class function.
classSong(object):def__init__(self,lyrics):# instantiation and shortcut for a creating a variableself.lyrics=lyrics# the variable could be equal to a text, a number or a variabledefsing_me_a_song(self):# create a class functionforlineinself.lyrics:printline# instance happy_bday=Song(["Happy birthday to you","I don't want to get sued","So I'll stop right there"])# instancebulls_on_parade=Song(["They rally around tha family","With pockets full of shells"])# instanceau_clair=Song(["Au clair de la lune","Mon ami Pierrot","Prete-moi ta plume","Pour ecrire un mot"])# not an instance!!!frere_jacques=["Frere Jacques (bis)","Dormez-vous (bis)","Sonnez les matines (bis)","Ding-din-don (bis)"]# instancefrere=Song(["Frere Jacques (bis)","Dormez-vous (bis)","Sonnez les matines (bis)","Ding-din-don (bis)"])# not a class functiondefchante_moi(paroles):# create a functionforligneinparoles:printligne
Invoke an instance.
happy_bday.sing_me_a_song()
123
Happy birthday to you
I don't want to get sued
So I'll stop right there
Again.
bulls_on_parade.sing_me_a_song()
12
They rally around tha family
With pockets full of shells
The script below (ex41.py) imports a word list from a text file (ex41_words.txt).
The script is a drill for learning oop.
importrandomimportsys## WORD_URL = "http://learncodethehardway.org/words.txt" # read a file http://learncodethehardway.org/words.txtWORD_TXT="ex41_words.txt"WORDS=[]# dictionary {"Python": "English"}PHRASES={"class %%%(%%%):":"Make a class named %%% that is-a %%%.","class %%%(object):\n\tdef __init__(self, ***):":"class %%% has-a __init__ that takes self and *** parameters.","class %%%(object):\n\tdef ***(self, @@@):":"class %%% has-a function named *** that takes self and @@@ parameters.","*** = %%%()":"Set *** to an instance of class %%%.","***.***(@@@)":"From *** get the *** function, and call it with parameters self, @@@.","***.*** = '***'":"From *** get the *** attribute and set it to '***'."}# do they want to drill phrases firstiflen(sys.argv)==2andsys.argv[1]=="English":PHRASE_FIRST=Trueelse:PHRASE_FIRST=False# load up the words from the website## for word in urlopen(WORD_URL).readlines():forwordinopen(WORD_TXT,"r").readlines():WORDS.append(word.strip())defconvert(snippet,phrase):# 'list comprehension', reseach on the Internetclass_names=[w.capitalize()forwinrandom.sample(WORDS,snippet.count("%%%"))]other_names=random.sample(WORDS,snippet.count("***"))results=[]param_names=[]foriinrange(0,snippet.count("@@@")):param_count=random.randint(1,3)param_names.append(', '.join(random.sample(WORDS,param_count)))forsentenceinsnippet,phrase:result=sentence[:]# fake class namesforwordinclass_names:result=result.replace("%%%",word,1)# fake other namesforwordinother_names:result=result.replace("***",word,1)# fake parameter listsforwordinparam_names:result=result.replace("@@@",word,1)results.append(result)returnresults# keep going until until they hit CTRL-Dtry:whileTrue:snippets=PHRASES.keys()random.shuffle(snippets)forsnippetinsnippets:phrase=PHRASES[snippet]question,answer=convert(snippet,phrase)ifPHRASE_FIRST:question,answer=answer,questionprintquestionraw_input("> ")print"ANSWER: %s\n\n"%answerexceptEOFError:print"\nBye"
123456789
alarm.deer(disgust, brass)
> deer is a Class alarm function that takes arguments digust and brass
ANSWER: From alarm get the deer function, and call it with parameters self, disgust, brass.
class Building(Blood):
> etc
ANSWER: Make a class named Building that is-a Blood.
bucket = Berry()
Sample of the original word list, 10 out of 503:
1 2 3 4 5 6 7 8 91011
text
account
achiever
actor
addition
adjustment
advertisement
advice
aftermath
agreement
airplane
Same script, but the list of word comes from the Internet.
A note on the script:
The use of constant variable such as WORD_URL (such variable should not be modified).
A constant variable can be anything from a number, a string to a dictionary.
The use of try/except pair to check for errors. It is similar to the pair if/else.
Therea are several types of errors. EOFError is just one type. Consult other (or online) manuals to find out about all the types of errors.
importrandomfromurllibimporturlopenimportsysWORD_URL="http://learncodethehardway.org/words.txt"# read a fileWORDS=[]# dictionary {"Python": "English"}PHRASES={"class %%%(%%%):":"Make a class named %%% that is-a %%%.","class %%%(object):\n\tdef __init__(self, ***)":"class %%% has-a __init__ that takes self and *** parameters.","class %%%(object):\n\tdef ***(self, @@@)":"class %%% has-a function named *** that takes self and @@@ parameters.","*** = %%%()":"Set *** to an instance of class %%%.","***.***(@@@)":"From *** get the *** function, and call it with parameters self, @@@.","***.*** = '***'":"From *** get the *** attribute and set it to '***'."}# do they want to drill phrases firstiflen(sys.argv)==2andsys.argv[1]=="English":PHRASE_FIRST=Trueelse:PHRASE_FIRST=False# load up the words from the websiteforwordinurlopen(WORD_URL).readlines():WORDS.append(word.strip())defconvert(snippet,phrase):# 'list comprehension', reseach on the Internetclass_names=[w.capitalize()forwinrandom.sample(WORDS,snippet.count("%%%"))]other_names=random.sample(WORDS,snippet.count("***"))results=[]param_names=[]foriinrange(0,snippet.count("@@@")):param_count=random.randint(1,3)param_names.append(', '.join(random.sample(WORDS,param_count)))forsentenceinsnippet,phrase:result=sentence[:]# fake class namesforwordinclass_names:result=result.replace("%%%",word,1)# fake other namesforwordinother_names:result=result.replace("***",word,1)# fake parameter listsforwordinparam_names:result=result.replace("@@@",word,1)results.append(result)returnresults# keep going until until they hit CTRL-Dtry:whileTrue:snippets=PHRASES.keys()random.shuffle(snippets)forsnippetinsnippets:phrase=PHRASES[snippet]question,answer=convert(snippet,phrase)ifPHRASE_FIRST:question,answer=answer,questionprintquestionraw_input("> ")print"ANSWER: %s\n\n"%answerexceptEOFError:print"\nBye"
classPerson(object):def__init__(self,name):## Person has-a nameself.name=name## Person has-a pet of some kind, but the pet is specifies elsewhere...self.pet=None
Employee is-a Person, Person is-a object.
classEmployee(Person):def__init__(self,name,salary):## Employee has-a name, because Person has-a name## super:super(Employee,self).__init__(name)## Employee has-a salaryself.salary=salary
Fish is-a object.
classFish(object):## no attributes like has-a namepass
Salmon is-a Fish, Fish is-a object.
classSalmon(Fish):## no attributes like has-a namepass
Halibut is-a Fish, Fish is-a object.
classHalibut(Fish):## no attributes like has-a namepass
rover is-a instance of name, Dog has-a name.
rover=Dog("Rover")
satan is-a instance of name, Cat has-a name.
satan=Cat("Satan")
mary is-a instance of name, Person has-a name.
mary=Person("Mary")
mary has-a Cat, Cat has-a name, satan, is-a Cat.
mary.pet=satan
frank is-a instance of name, salary, Employee has-a name, salary.
frank=Employee("Frank",120000)
frank has-a Dog, Dog has-a name, rover, is-a Dog.
frank.pet=rover
flipper is-a instance of Fish, Fish is-a object, both has-a not attributes.
flipper=Fish()
crouse is-a instance of Salmon, Salmon is-a Fish; both has-a not attribute.
crouse=Salmon()
harry is-a instance of Halibut, Halibut is-a Fish; both has-a not attribute.
harry=Halibut()
Wrap-up.
object
class Fish(object)
class Salmon(Fish)
crouse = Salmon()
class Halibut(Fish)
harry = Halibut()
flipper = Fish()
class Animal(object)
class Dog(Animal)
rover = Dog("Rover") has-a name
class Cat(Animal)
satan = Cat("Satan") has-a name
class Person(object)
mary.pet = satan has-a name, pet
class Employee(Person)
frank = Employee ("Frank", 120000) has-a name, salary
frank.pet = rover has-a pet
The concept of inheritance, and those of implicit inheritance, overridden inheritance, multiple inheritance, composition, alteration, super objects (or ‘reinheritance’) are explained in Exercise 44.
This Exercise is the first to prepare the final project (Exercise 52, the last chapter). Let’s create a game, from A to Z. First, start by planning. This methodology is valuable for planning any kind of project or program.
Methodology
1- Write about the problem:
“Aliens have invaded a space ship and our hero has to go through a maze of rooms defeating them so he can escape into an escape pod to the planet below. The game will be more like a Zork or Adventure type game with text outputs and funny ways to die. The game will involve an engine that runs a map full of rooms or scenes. Each room will print its own description when the player enters it and then tell the engine what room to run next out of the map.”
2- Describe each scene:
Death
This is when the player dies and should be something funny.
Central Corridor
This is the starting point and has a Gothon already standing there they have to defeat with a joke before continuing.
Laser Weapon Armory
This is where the hero gets a neutron bomb to blow up the ship before getting to the escape pod. It has a keypad the hero has to guess the number for.
The Bridge
Another battle scene with a Gothon where the hero places the bomb.
Escape Pod
Where the hero escapes but only after guessing the right escape pod.
3- Draw a map, write more descriptions.
4- Extract key concepts:
1 concept = 1 class.
Research them, deepen things.
Nouns = concepts = classes:
Alien
Player
Ship
Maze
Room
Scene
Gothon
Escape Pod
Planet
Map
Engine
Death
Central Corridor
Laser Weapon Armory
The Bridge
Verbs = functions.
This is par the PEP: classes should be in an explicit noun startin with a uppercased letter such as class Central Corridor(). Functions should be verbs such as def play():.
5- Create a class Hierarchy and object Map
Make a class Hierarchy:
Map
Engine
Scene
Death
Central Corridor
Laser Weapon Armory
The Bridge
Escape Pod
PEP: I know from the description I’m going to need a way to ‘run’ the engine, ‘get the next scene’ from the map, get the ‘opening scene’, and ‘enter’ a scene. I’ll add those like this:
Map
next_scene
opening_scene
Engine
play
Scene
enter
Death
Central Corridor
Laser Weapon Armory
The Bridge
Escape Pod
All the scenes under another scene will inherit it; except ‘enter’: override it later.
6- Code the Classes and a Test to Run Them:
Turn:
- Map
- next_scene (verb)
- opening scene (verb)
- Engine
- play (verb)
- Scene
- enter (verb)
- Death
- Central Corridor
- Laser Weapon Armory
- The Bridge
- Escape Pod
Into:
class Map(object):
def __init__(self, start_scene):
def next_scene(self, start_scene):
def opening_scene(self):
class Engine(object):
def __init__(self, scene_map):
def play(self):
class Scene(object):
def enter(self):
class CentralCorridor(Scene):
def enter(self):
class LaserWeaponArmory(Scene):
def enter(self):
class TheBridge(Scene):
def enter(self):
class EscapePod(Scene):
def enter(self):
class Death(Scene):
def enter(self):
a_map = Map('central_corridor')
a_game = Engine(a_map)
a_game.play()
Into:
class Scene(object):
def enter(self):
pass
class Engine(object):
def __init__(self, scene_map):
pass
def play(self):
pass
class Death(Scene):
def enter(self):
pass
class CentralCorridor(Scene):
def enter(self):
pass
def enter(self):
pass
class TheBridge(Scene):
def enter(self):
pass
class EscapePod(Scene):
def enter(self):
pass
class Map(object):
def __init__(self, start_scene):
pass
def next_scene(self, scene_name):
pass
def opening_scene(self):
pass
a_map = Map('central_corridor')
a_game = Engine(a_map)
a_game.play()
# import two functions from two librariesfromsysimportexitfromrandomimportrandint# class to generate child classesclassScene(object):defenter(self):print"This scene is not yet configured. Subclass it and implement enter()."exit(1)classEngine(object):def__init__(self,scene_map):self.scene_map=scene_mapdefplay(self):current_scene=self.scene_map.opening_scene()# instance of class Engine(object), __init__(self, scene_map) with method/function opening_scene(self) from class Map(object) belowlast_scene=self.scene_map.next_scene('finished')# instance of class Engine(object), __init__(self, scene_map) with method/function next_scene(self, scene_name) from class Map(object) belowwhilecurrent_scene!=last_scene:next_scene_name=current_scene.enter()# function/method from class Scene(object) abovecurrent_scene=self.scene_map.next_scene(next_scene_name)# instance of class Engine(object), __init__(self, scene_map) with method/function next_scene(self, scene_name) from class Map(object)current_scene.enter()# use newly-created current_scene with function/method from class Scene(object) aboveclassDeath(Scene):quips=["You died. You kinda suck at this.","Your mom would be proud...if she were smarter.","Such a louser.","I have a small puppy that's better at this."]# a list (variable) where a random method will extract an elementdefenter(self):printDeath.quips[randint(0,len(self.quips)-1)]# use class Death(object)'s variable and run a randint method; randint(1st random element from a number of elements contain in the list)exit(1)classCentralCorridor(Scene):defenter(self):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"The Gothons of Planet Percal #25 have invaded your ship and destroyed"print"your entire crew. You are the last surviving member and your last"print"mission is to get the neutron destruct bomb from the Weapons Armory,"print"put it in the bridge, and blow the ship up after getting into an "print"escape pod."print"\n"print"You're running down the central corridor to the Weapons Armory when"print"a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume"print"flowing around his hate filled body. He's blocking the door to the"print"Armory and about to pull a weapon to blast you."action=raw_input("shoot!/dodge!/tell a joke> ")ifaction=="shoot!":print"Quick on the draw you yank out your blaster and fire it at the Gothon."print"His clown costume is flowing and moving around his body, which throws"print"off your aim. Your laser hits his costume but misses him entirely. This"print"completely ruins his brand new costume his mother bought him, which"print"makes him fly into an insane rage and blast you repeatedly in the face until"print"you are dead. Then he eats you."return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelifaction=="dodge!":print"Like a world class boxer you dodge, weave, slip and slide right"print"as the Gothon's blaster cranks a laser past your head."print"In the middle of your artful dodge your foot slips and you"print"bang your head on the metal wall and pass out."print"You wake up shortly after only to die as the Gothon stomps on"print"your head and eats you."return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelifaction=="tell a joke":print"Lucky for you they made you learn Gothon insults in the academy."print"You tell the one Gothon joke you know:"print"Lbhe zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr, fur fvgf nebhaq gur ubhfr."print"The Gothon stops, tries not to laugh, then busts out laughing and can't move."print"While he's laughing you run up and shoot him square in the head"print"putting him down, then jump through the Weapon Armory door."return'laser_weapon_armory'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"DOES NOT COMPUTE!"return'central_corridor'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassLaserWeaponArmory(Scene):defenter(self):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"You do a dive roll into the Weapon Armory, crouch and scan the room"print"for more Gothons that might be hiding. It's dead quiet, too quiet."print"You stand up and run to the far side of the room and find the"print"neutron bomb in its container. There's a keypad lock on the box"print"and you need the code to get the bomb out. If you get the code"print"wrong 10 times then the lock closes forever and you can't"print"get the bomb. The code is 3 digits."code="%d%d%d"%(1,2,3)#% (randint(1,9), randint(1,9), randint(1,9))guess=raw_input("[keypad]> ")guesses=0whileguess!=codeandguesses<10:print"BZZZZEDDD!"guesses+=1guess=raw_input("[keypad]> ")ifguess==code:print"The container clicks open and the seal breaks, letting gas out."print"You grab the neutron bomb and run as fast as you can to the"print"bridge where you must place it in the right spot."return'the_bridge'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"The lock buzzes one last time and then you hear a sickening"print"melting sound as the mechanism is fused together."print"You decide to sit there, and finally the Gothons blow up the"print"ship from their ship and you die."return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassTheBridge(Scene):defenter(self):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"You burst onto the Bridge with the netron destruct bomb"print"under your arm and surprise 5 Gothons who are trying to"print"take control of the ship. Each of them has an even uglier"print"clown costume than the last. They haven't pulled their"print"weapons out yet, as they see the active bomb under your"print"arm and don't want to set it off."action=raw_input("throw the bomb/slowly place the bomb> ")ifaction=="throw the bomb":print"In a panic you throw the bomb at the group of Gothons"print"and make a leap for the door. Right as you drop it a"print"Gothon shoots you right in the back killing you."print"As you die you see another Gothon frantically try to disarm"print"the bomb. You die knowing they will probably blow up when"print"it goes off."return'death'elifaction=="slowly place the bomb":print"You point your blaster at the bomb under your arm"print"and the Gothons put their hands up and start to sweat."print"You inch backward to the door, open it, and then carefully"print"place the bomb on the floor, pointing your blaster at it."print"You then jump back through the door, punch the close button"print"and blast the lock so the Gothons can't get out."print"Now that the bomb is placed you run to the escape pod to"print"get off this tin can."return'escape_pod'else:print"DOES NOT COMPUTE!"return"the_bridge"# input for class Map(object)'s dictionary of key:value; extract a function from another class classEscapePod(Scene):defenter(self):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"You rush through the ship desperately trying to make it to"print"the escape pod before the whole ship explodes. It seems like"print"hardly any Gothons are on the ship, so your run is clear of"print"interference. You get to the chamber with the escape pods, and"print"now need to pick one to take. Some of them could be damaged"print"but you don't have time to look. There's 5 pods, which one"print"do you take?"good_pod=1#randint(1,5)guess=raw_input("[pod #]> ")ifint(guess)!=good_pod:print"You jump into pod %s and hit the eject button."%guessprint"The pod escapes out into the void of space, then"print"implodes as the hull ruptures, crushing your body"print"into jam jelly."return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"You jump into pod %s and hit the eject button."%guessprint"The pod easily slides out into space heading to"print"the planet below. As it flies to the planet, you look"print"back and see your ship implode then explode like a"print"bright star, taking out the Gothon ship at the same"print"time. You won!"return'finished'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassFinished(Scene):defenter(self):print"You won! Good job."return'finished'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassMap(object):scenes={'central_corridor':CentralCorridor(),'laser_weapon_armory':LaserWeaponArmory(),'the_bridge':TheBridge(),'escape_pod':EscapePod(),'death':Death(),'finished':Finished(),}def__init__(self,start_scene):self.start_scene=start_scenedefnext_scene(self,scene_name):val=Map.scenes.get(scene_name)returnvaldefopening_scene(self):returnself.next_scene(self.start_scene)a_map=Map('central_corridor')a_game=Engine(a_map)a_game.play()
Improve…
# import two functions from two librariesfromsysimportexitfromrandomimportrandintimporttimeimportmath# class to generate child classesclassScene(object):defenter(self):print"This scene is not yet configured. Subclass it and implement enter()."exit(1)classEngine(object):def__init__(self,scene_map,hero):self.scene_map=scene_mapself.hero=herodefplay(self):current_scene=self.scene_map.opening_scene()# instance of class Engine(object), __init__(self, scene_map) with method/function opening_scene(self) from class Map(object) belowlast_scene=self.scene_map.next_scene('finished')# instance of class Engine(object), __init__(self, scene_map) with method/function next_scene(self, scene_name) from class Map(object) belowwhilecurrent_scene!=last_scene:# True:print"\n----------"next_scene_name=current_scene.enter(self.hero)# function/method from class Scene(object) abovecurrent_scene=self.scene_map.next_scene(next_scene_name)# instance of class Engine(object), __init__(self, scene_map) with method/function next_scene(self, scene_name) from class Map(object)current_scene.enter()# use newly-created current_scene with function/method from class Scene(object) aboveclassDeath(Scene):quips=["Death1","Death2","Death3","Death4"]# a list (variable) where a random method will extract an elementdefenter(self,hero):printDeath.quips[randint(0,len(self.quips)-1)]# use class Death(object)'s variable and run a randint method; randint(1st random element from a number of elements contain in the list)exit(1)classCentralCorridor(Scene):defenter(self,hero):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"Enter. Select."action=raw_input("Pick one: a/b/c> ").upper()ifaction=="A":print"Ouch!"return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelifaction=="B":print"Aye!"return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelifaction=="C":print"Good."return'laser_weapon_armory'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"DOES NOT COMPUTE!"return'central_corridor'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassLaserWeaponArmory(Scene):defenter(self,hero):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"Pick a 3-digit combinaison."code="%d%d%d"%(1,2,3)#% (randint(1,9), randint(1,9), randint(1,9))printcodeguess=raw_input("[keypad]> ")guesses=0whileguess!=codeandguesses<10:print"BZZZZEDDD!"guesses+=1guess=raw_input("[keypad]> ")ifguess==code:print"Click! Go!"return'the_bridge'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"Boom!"return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassTheBridge(Scene):defenter(self,hero):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"Bridge enigma."action=raw_input("true/false> ").upper()ifaction=="TRUE"oraction=="T":print"It goes off."return'death'elifaction=="FALSE"oraction=="F":print"Escape."return'escape_pod'else:print"DOES NOT COMPUTE!"return"the_bridge"# input for class Map(object)'s dictionary of key:value; extract a function from another class classEscapePod(Scene):defenter(self,hero):# the following will print whenever you call CentralCorridor.enter() function/method elsewhereprint"You rush!"good_pod=1#randint(1,5)guess=raw_input("[Pick a pod #]> ")ifint(guess)!=good_pod:print"Oups!"return'death'# input for class Map(object)'s dictionary of key:value; extract a function from another classelse:print"Good choice!"return'finished'# input for class Map(object)'s dictionary of key:value; extract a function from another classclassWin(Scene):defenter(self,hero):print"You won! Good job."return'finished'# input for class Map(object)'s dictionary of key:value; extract a function from another class# exit(0)classFinal(Scene):defenter(self,hero)monster=Monster("Gothon")print"%s, You now came across the final boss %s! Let's fight!!!"%(hero.name,monster.name)a_combat=Combat()next_stage=a_combat.combat(hero,monster)returnnext_stageclassCombat(object):defcombat(self,hero,monster):#combat between two rolesround=1whileTrue:print'='*30print'round %d'%roundprint'='*30print"Your HP: %d"%hero.hpprint"%s's HP: %d"%(monster.name,monster.hp)print'Which action do you want to take?'print'-'*10print'1) attack - Attack the enemy'print'2) defend - Defend from being attacked, also will recover a bit'try:action=int(raw_input('> '))exceptValueError:print"Please enter a number!!"continue# defending should be done before attackingifaction==2:hero.defend()# action of monster, 1/5 possibility it will defendsmonster_action=randint(1,6)ifmonster_action==5:monster.defend()ifaction==1:hero.attack(monster)elifaction==2:passelse:print"No such action!"ifmonster_action<5:monster.attack(hero)# whether win or dieifhero.hp<=0:return'death'ifmonster.hp<=0:return'win'hero.rest()monster.rest()round+=1classMap(object):scenes={'central_corridor':CentralCorridor(),'laser_weapon_armory':LaserWeaponArmory(),'the_bridge':TheBridge(),'escape_pod':EscapePod(),'death':Death(),'final_fight':Final(),'win':Win(),'finished':Finished(),}def__init__(self,start_scene):self.start_scene=start_scenedefnext_scene(self,scene_name):val=Map.scenes.get(scene_name)returnvaldefopening_scene(self):returnself.next_scene(self.start_scene)classhuman(object):defending=0def__init__(self,name):self.name=namedefattack(self,target):# attack the targetpercent=0time.sleep(1)iftarget.defending==1:percent=float(self.power)/10.0+randint(0,10)target.hp=math.floor(target.hp-percent)else:percent=float(self.power)/5.0+randint(0,10)target.hp=math.floor(target.hp-percent)print"%s attack %s. %s's HP decreased by %d points."%(self.name,target.name,target.name,percent)defdefend(self):# be in the defending stateself.defending=1print"%s is trying to defend."%self.namedefrest(self):# recover a bit after each roundifself.defending==1:percent=self.rate*10+randint(0,10)else:percent=self.rate*2+randint(0,10)self.hp+=percentprint"%s's HP increased by %d after rest."%(self.name,percent)self.defending=0classHero(Human):# class for herohp=1000power=200rate=5classMonster(Human):# class for monsterhp=5000power=250rate=5a_map=Map('central_corridor')a_hero=Hero('Joe')a_game=Engine(a_map)a_game.play()
The question of ‘inheritance versus composition’ comes down to an attempt to solve the problem of reusable code.
You don’t want to have duplicated code all over your software, since that’s not clean and efficient.
Inheritance: solves this problem by creating a mechanism for you to have implied features in base classes.
Composition: solves this by giving you modules and the ability to call functions in other classes.
If both solutions solve the problem of reuse, then which one is appropriate in which situations? The answer is incredibly subjective, but I’ll give you my three guidelines for when to do which:
Avoid multiple Inheritance at all costs, as it’s too complex to be reliable. If you’re stuck with it, then be prepared to know the class hierarchy and spend time finding where everything is coming from.
Use Composition to package code into modules that are used in many different unrelated places and situations.
Use Inheritance only when there are clearly related reusable pieces of code that fit under a single common concept or if you have to because of something you’re using.
The thing to remember about object-oriented programming is that it is entirely a social convention programmers have created to package and share code. In that case, find out how they use things and then just adapt to the situation.
A class does things: name it as if it’s a command you are giving to the class. Same as pop is saying ‘pop this off the list’.
Keep functions small and simple (PEP).
Class Style
Use the camel case: SuperGoldFactory.
Minimize what __init__ does. It should be simple to use.
Other class functions use the underscore format: my_awesome_hair.
Be consistent in how you organize your function arguments. Function 1 takes (dog, cat, user), function 2 should take (dog, cat, user). Unless there is a good reason.
Variable should be self-contained. Limit importing from modules or globals.
Always have a class Name(object) on top of all.
Code Style
Give your code vertical space to read.
Read you code out loud to test it. Change the difficult passages to improve readibility.
Imitate other coders: find you style.
Respect others’s style; be a team player.
Good Comments
Describe why you are doing doing what you are doing.
Write for the others.
Write sentences.
Avoid clutering the code though. Short sentences, to the point.
In this code I’m not using the name Parent, since there is not a parent-child is-a relationship. This is a has-a relationship, where Child has-a Other that it uses to get its work done.
classOther(object):defimplicit(self):print"OTHER implicit()"defoverride(self):print"OTHER override()"defaltered(self):print"OTHER altered()"classChild(object):def__init__(self):self.other=Other()# initialize this class with Other(), when an instance is created, it will inherit the class member variables, class functions...defimplicit(self):self.other.implicit()# call the other class function defoverride(self):print"CHILD override()"defaltered(self):print"CHILD, BEFORE OTHER altered()"self.other.altered()# call the other class functionprint"CHILD, AFTER OTHER altered()"son=Child()# instanceson.implicit()son.override()son.altered()
Actions on the child imply an action on the parent.
The use of pass under the class Child: is how you tell Python that you want an empty block. This creates a class named Child but says that there’s nothing new to define in it. Instead it will inherit all of its behavior from Parent.
If you put functions in a base class (i.e., Parent) then all subclasses (i.e., Child) will automatically get those features. Very handy for repetitive code you need in many classes.
Python has to look-up the possible function in the class hierarchy for both Child and BadStuff, but it needs to do this in a consistent order. To do this Python uses “method resolution order” (MRO) and an algorithm called C3 to get it straight.
Because the MRO is complex and a well-defined algorithm is used, Python can’t leave it to you to get the MRO right. Instead, Python gives you the super() function, which handles all of this for you in the places that you need the altering type of actions as I did in Child.altered. With super() you don’t have to worry about getting this right, and Python will find the right function for you.
Actions on the child override the action on the parent.
As you can see, it runs the Parent.override function because that variable (dad) is a Parent. But it also runs Child.override messages because son is an instance of Child and Child overrides that function by defining its own version.
Actions on the child alter the action on the parent.
son.altered() overrides Parent.altered the Child.altered version runs, and line 9 executes like you’d expect. In this case I want to do a before and after, I want to use super to get the Parent.altered version. I call super(Child, self).altered(), which is aware of inheritance and will get the Parent class for you. You should be able to read this as “call super with arguments Child and self, then call the function altered on whatever it returns.” At this point, the Parent.altered version of the function runs, and that prints out the Parent message. Finally, this returns from the Parent.altered and the Child.altered function continues to print out the after message.
classParent(object):defaltered(self):print"PARENT altered()"classChild(Parent):defaltered(self):print"CHILD, BEFORE PARENT altered()"super(Child,self).altered()print"CHILD, AFTER PARENT altered()"dad=Parent()son=Child()dad.altered()son.altered()
Use an existing project, Exercise 43 for example, and adapt it. This is a first draft for a project…
1
Storyboarding tool.
Create a program that would question the user on its data and advise him on what would be the best graphics to use. Frame by frame, the user could build a presentation knowing slide 1 should be a histogram, slide 2 a scatter plot, etc.
2
Map
next_graph
opening comment (verb)
Engine
choose (verb)
Graph
proceed (verb)
1. CC pie
2. IC bar
3. TSC column, line
4. FDC column, line
5. CorC bar, dot
opening comment
general comment
storytelling
pie
compare data, y, n
y, stacked bar chart
n, pie chart with a maximum of 6 items
bar
simple series of data or items: h deviation bar chart (tornado), divide A from B (winners from losers, good markets from bad markets): h deviation bar chart (tornado), mix of two components (portfolio A items vs portfolio B items):sliding h bar chart, high-low spreads:range h bar chart, correlation x1 and x2 with y (two products, two markets… with): paired bar chart, compare aspects (with or without discount, red or blue paint):group h bar chart, components of the total: subdivided h bar chart…
column
p.37, 42
line
p.39, 44-45
surface
p. 40
dot
p.49
3
Create module 3graph_story (proof of concept).
The module presents a story in 3 graphs, according to 3 sets of data.
class Map(object):
def __init__(self,start):
def next(self, start):
def opening(self):
class Engine(object):
def __init__(self,graph_map):
def choose(self):
class Graph(object):
def proceed(self):
class 1CC(Graph):
def enter(self)
pie
class 2IC(Graph):
def enter(self):
bar
class 3TSC(Graph):
def enter(self):
column
line
class 4FDC(Graph):
def enter(self):
column
line
class 5CorC(Graph):
def enter(self):
bar
dot
\:. is the project parent directory or simply ‘the’ directory (its name is the project’s name).
The directory is the place to be when launching scripts.
bin is the main sub-directory. It contains the main script (python bin/main.py) for launching other scripts in the project; and launching tests as well. These script are often located in other sub-directories.
A sub-directory must be executable to import a module from it or execute a script in it: add an empty script called __init__.py.
When a script is executed, it is compiled. Another script, with the extension .pyc, appears. Same as for __init__.pyc, as the sub-directory was executed (when a script import a script from another sub-directory for example).
tests contains files to perform nose tests and unittests.
setup.py is for documenting and distributing the project (when the project is compiled to be launched as a whole or frozen to be distributed).
You can add a readme file below (usually a text or markdown document).
The docs sub-directory contains all the project’s documentation. It is more elaborate than the ‘readme’ file: manuals, explanations, logs, wikis, etc.
There can be other sub-directories for static such as images, web languages, etc.
Repeat this directory structure for every project.
Test if you migrated the files correctly. In the bash:
grep -r NAME * # no traces of 'NAME', from 'skeleton'
find . -name "*.pyc" -exec rm {}\;# no trace of 'name'
When you launch a script, you launch it from the parent directory with python bin/app.py.
In directory ‘ex47’, run tests with python tests/BLAH_tests.py.
Consult the manual about testing. This is not covered in this notebook.
Testing must be done in the shell or in the bash. Make sure you’re running the tests with nosetests not with just Python.
The important functions here are assert_equal which makes sure that variables you have set or paths you have built in a Room are actually what you think they are. If you get the wrong result, then nosetests will print out an error message so you can go figure it out.
In a script, when you import from another sub-directory, code:
fromex47.gameimportRoom
When the imported script is in the same sub-directory, code: