object-oriented programming (review + a few new tidbits) "python programming for the absolute...
TRANSCRIPT
Object-oriented Programming (review +
a few new tidbits)
• "Python Programming for the Absolute Beginner, 3rd ed." Chapters 8 & 9
• Python 3.2 reference
Basic OOP…hopefully review
1. Absolute basicsa. Creating instances of a classb. Defining / calling methods
a. Role of self
2. Making attributes (and the role of constructor)3. __str__ method4. Inheritance
a. Adding methodsb. Modifying methodsc. Modifying + using-original methods.
Misc. New Topics5. Making modules6. isinstance function (and inheritance)
a. numbers.Number class
7. __class__ attribute8. Private methods / attributes.
a. Controls access (safeguards) to the variableb. Makes your class more robust, error-proof
i. You know the attribute can't be modified outside of the class.
c. Good software engineering / style.
9. Properties (and decorators intro)10. (More) automatically-called methods.11. __name__ variable (and "__main__")12. Exceptions
a. Handling exceptionsb. Raising exceptions
1. (OOP) Absolute basics# A class is a blueprint for a new python type.class Ship(object):
""" A spaceship! """def alert(self):
""" A simple method """print("RED-ALERT!")
# An object (instance) is a variable built using# a class blueprint.S = Ship()Ship.alert(S) # Calling method through the class
# You must pass an argument for self. S.alert() # Calling method through an instance
# (the preferred way). S is # automatically passed by python.
docstrings
2. (OOP) Making attributes
# An attribute is a variable assiciated # with a variable.
# First way (using S from above)S.health = 100
# You can use the attribute as a normal var.S.health -= 1print(S.health)
2 (OOP) Making Attributes, cont.• Problem: You aren't guaranteed that all instances of the
ship class will have a health attribute…
class Ship(object):def takeDamage(self, dmg):
self.health -= dmgS = Ship()S.health = 100S.takeDamage(5)print(S.health)T = Ship()T.takeDamage(4) # Problem!
2. (OOP) Making Attributes, cont.
• A better method: the constructor– A method, which if defined, is called automatically when a new
instance is created.– In python, it must be called __init__
class Ship(object):def __init__(self):
""" The constructor """print("I'm a new ship!")
S = Ship() # Python calls __init__ for you. # self and S will (for this call) # both point to the same object.
2. (OOP) Making Attributes, cont.• Since the constructor is called when the object is created…
– …if you create attributes here, you can be sure every instance will have one
class Ship(object):def __init__(self, startHealth):
""" The constructor """self.health = startHealth
def takeDamage(self, dmg):self.health -= dmg
S = Ship(100) # The 100 is passed for startHealthT = Ship(50)S.takeDamage(5)T.takeDamage(5)
3. (OOP) __str__ method
• Another special method that, if defined, is called automatically by python when needed.
• In this case, it is called, when an object needs to be converted to a string.
S = Ship(100)x = str(S)# x will hold # '<__main__.Ship object at 0x02892bb0>'print(S) # Prints a string like that in x
3. (OOP) __str__, cont.• But…if we define the __str__ method, we can change the
string generated…
class Ship(object):def __init__(self, startHealth):
self.health = startHealthdef __str__(self):
return "A ship. hp=" + str(self.health)
S = Ship(100)print(S)
• Note: Doesn't print a string; it returns one.• Note2: Not every method has to start/end with __ (see
takeDamage from before)
4. (OOP) Inheritance• Inheritance is a way of making a new class from an
existing one– Alternative: copy-and-paste code• Disadvantage1: (A lot) more code – harder to read• Disadvantage2: If the original class changes, you have to
remember to copy-paste everywhere it was copied.
• Once you've used inheritance to create a new class, you can…– Add new methods– Modify (sort-of replace) inherited methods– If you want more attributes, you often modify the
__init__ method.
4 (OOP) Inheritance, cont.• A basic exampleclass Parent(object):
def __init__(self, x):self.x = x
def f(self):# Do something…
class Child(Parent):def h(self):
# Do something…
A = Parent(5)A.f()B = Child(5) # Note how we inherited __init__B.f() # ...and fB.h() # We also have a new method.
4 (OOP) Inheritance, cont.• "Replacing" methods# Parent is as beforeclass Child(Parent):
# As beforedef f(self): # Note Parent had an f
# method. We're "replacing" it
B = Child(5)B.f() # Calls the f method from the Child class.# Recall…Child.f(B) # Same as the previous line.
4 (OOP) Inheritance, cont.• Let's say we want the child to do everything in
the Parent's version of f, then do something else afterwards…
• Option I: Copy-paste (same problems as before)• Option II: Use the "calling-a-method-through-a-
class" call convention
class Child(Parent):def f(self):
Parent.f(self)# Do something new here…
4 (OOP) Inheritance, cont.
• So…to add new attributes in a derived class, follow the same pattern for __init__.
class Ship(object):def __init__(self, startHealth):
self.health = startHealthclass Destroyer(Ship):
def __init__(self, startHealth, laserPow):Ship.__init__(self, startHealth)self.power = laserPow
D = Destroyer(100, 10)print(D.health) # Created in Ship.__init__print(D.power) # Created in Destroyer.__init__
Now for the new stuff!
5. Making Modules
• A collection of "stuff" in a .py file– variables– classes– functions
• Import it with an import– leave off the .py– must be in the same directory
5. Making modules, cont.class FooClass(object):
def bar(self):# Does something
class fun(x):# Does something
avar = "a module variable!"
import foo
F = foo.FooClass()F.bar() # Note: don't need foo...
foo.fun(5)
print(foo.avar)
foo.py
user.py
6. isinstance function
• One way to determine if an object is:– an instance of a class x– an instance of a class derived from x
• With built-in types– Suppose x could hold an int, float, …isinstance(5, int) # Trueisinstance(3.1, int) # Falseisinstance(3.1, float) # Trueisinstance(5, numbers.Number) # Trueisinstance(3.1, numbers.Number) # True# Note: numbers.Number is the base class for # int's and float's (and complex)# Note2: you must import numbers to use it
6. isinstance function, cont.
class A(object):pass
class B(A):pass
x = B()isinstance(x, B) # Trueisinstance(x, int) # Falseisinstance(x, A) # True!
7. __class__ attribute (of objects)• The __class__ attribute of an object
– Holds a reference to the class this was built from– Can be changed (if you're careful)
class A(object):def f(self):
# …class B(A):
def f(self):# …
class C(A):def f(self):
# …x = B()print(x.__class__) # '<class "__main__.B">'x.__class__ = C # Changed the "type" of xprint(x.__class__) # '<class "__main__.C">'
9. Properties and Decorators• Decorators: advanced python black magic• An example of the way we'll use it:class Ship(object):
def __init__(self, startHealth):self.health = startHealth
@propertydef hp(self):
return self.health
@hp.setterdef hp(self, newVal):
self.health = int(newVal)
S = Ship(100)print(S.hp) # Note: there is actually no hp attribute…S.hp = 95 # Actually (here) changes self.health to 95.
10. Other built-in class "hooks"• Let's say we want to add / subtract from a ship's
health like this:S += 5 # Add 5 health (not over 100)S -= 2 # Subtract 2 health (not below 0)• Normally, this would cause an error– Python doesn't know how to add a Ship object and an
integer.– We can "tell it" how to with a "hook" function• Similar to __init__ and __str__ that we've seen already.
10. Other built-in "hooks", cont.
• To make the previous code work…class Ship(object):
def __init__(self, startHealth):self.health = startHealth
def __add__(self, rightHandSide):self.health = min(self.health + rightHandSide,
100)def __sub__(self, rightHandSide):
self.health = max(self.health – rightHandSide,0)
S = Ship(50)S = S + 5 # To python, S = S.__add__(5)S = S – 2 # To python, S = S.__sub__(2)
10. Other built-in "hooks", cont.
• We'll use these in Lab1:def __len__(self): …def __getitem__(self, index): …def __setitem__(self, index, newVal): …
• We'll use these later:def __truediv__(self, rightHandSide)def __mul__(self, rightHandSide)def __rmul__(self, leftHandSide)…
11. the __name__ variable
• A special variable set to either:– The name of the module (if this file was imported)– "__main__" if this module was run directly
• Suppose test.py is run below
def test():print(__name__)
test.py
import testprint(__name__) # "__main__"test.test() # "test"
test2.py
11. the __name__ variable, cont.
• The way we'll use it:
class VectorN(object):…
if __name__ == "__main__":# Put test code here.# It won't be run if we're using
(importing)
12. Exceptions
• Every time you get an error, you see an error similar to…
Traceback (most recent call last): File "Z:\etgg1802\test2.py", line 14, in <module> mainFunc() File "Z:\etgg1802\test2.py", line 12, in mainFunc subFunc() File "Z:\etgg1802\test2.py", line 8, in subFunc print(5 / 0)ZeroDivisionError: division by zero
The type of error Error description
The error happened here
We called got there from here…
…which we got to from here…
12. Exceptions, cont.
• Up to now, we've just been using these to debug.
• There are, however, two aspects to exceptions:– Exception Handling: attempting to recover from
an exception (without crashing the program)– Exception Raising: creating an exception to
indicate an error (common in modules)
12. Exceptions, cont.
• Raising Exceptionsraise ExceptionType(ErrorMessage)
• Example:if not isinstance(x, int):
raise TypeError("You must pass an int!")
• Some built-in exceptionso ZeroDivisionErroro IndexErroro TypeErroro ValueErroro …
• You can even create your own custom exceptions
12. Exceptions, cont.
• Handling (we probably won't need it in this class), but…try:
# Put code the could fail hereexcept ZeroDivisionError:
# Put code to handle (ignore) Zero-divideexcept ValueError:
# …except:
# Put code to handle any other error here
13. hasattr
• Useful to see if an object has a method or nothasattr(object, methodNameString) -> Booleanhasattr((1,2,3), "__len__") # Returns Truehasattr(5, "lower") # Returns Falsehasattr("AB", "lower") # Returns Truehasattr(Player1, "fire") # ???
Further Reading
• If you're struggling with python, you might try…– http://docs.python.org/3.2/tutorial/index.html– http://
en.wikibooks.org/wiki/Non-Programmer%27s_Tutorial_for_Python_3
– http://en.wikibooks.org/wiki/Python_Programming– Re-visit old ETGG1801 labs (maybe from the other
teacher too)– Buying a book– Coming to my office hours (a lot)– Get a tutor