the mirror of __init__
is __del__
(it is the tear down during clean up)
class Bear:
def __init__(self,name):
self.name = name
print(" made a bear called %s" % (name))
def __del__(self):
print("Bang! %s is no longer." % self.name)
y = Bear("Yogi") ; c = Bear("Cal")
del y; del c
## note that I'm assigning y twice here
y = Bear("Yogi") ; y = Bear("Cal")
If we quit (not from the notebook but the interpreter or ipython)
>>> f = Bear("Fuzzy")
` made a bear called Fuzzy`
>>> exit()
`Bang! Fuzzy is no longer.`
BootCamp>
%%file bear.py
import datetime
class Bear:
logfile_name = "bear.log"
bear_num = 0
all_bear_names = []
def __init__(self,name):
self.name = name
print((" made a bear called %s" % (name)))
self.logf = open(Bear.logfile_name,"a")
Bear.bear_num += 1
self.my_num = Bear.bear_num
self.logf.write("[%s] created bear #%i named %s\n" % \
(datetime.datetime.now(),Bear.bear_num,self.name))
self.logf.flush()
def growl(self,nbeep=5):
print(("\a"*nbeep))
def __del__(self):
print(("Bang! %s is no longer." % self.name))
self.logf.write("[%s] deleted bear #%i named %s\n" % \
(datetime.datetime.now(),self.my_num,self.name))
self.logf.flush()
# decrement the number of bears in the population
Bear.bear_num -= 1
# dont really need to close because Python will do the garbage collection
# for us. but it cannot hurt to be graceful here.
self.logf.close()
def __str__(self):
return " name = %s bear number = %i (population %i)" % \
(self.name, self.my_num,Bear.bear_num)
!rm bear.log
%run bear
a = Bear("Yogi")
b = Bear("Yogi")
b = a
b = Bear("Fuzzy")
Bear.bear_num
del a; del b
Bear.bear_num
!cat bear.log
__str__
is a method that defines how a Class should represent itself as a string
it takes only self as an arg, must return a string
run bear
b = Bear("Fuzzy")
print(b)
a = Bear("Yogi")
print(a)
this is the kind of formatting that datetime() is doing in it's own __str__
%%file bear2.py
import datetime
class Bear:
logfile_name = "bear.log"
bear_num = 0
def __init__(self,name):
self.name = name
print(" made a bear called %s" % (name))
self.logf = open(Bear.logfile_name,"a")
Bear.bear_num += 1
self.created = datetime.datetime.now()
self.my_num = Bear.bear_num
self.logf.write("[%s] created bear #%i named %s\n" % \
(datetime.datetime.now(),Bear.bear_num,self.name))
self.logf.flush()
def growl(self,nbeep=5):
print("\a"*nbeep)
def __del__(self):
print("Bang! %s is no longer." % self.name)
self.logf.write("[%s] deleted bear #%i named %s\n" % \
(datetime.datetime.now(),self.my_num,self.name))
self.logf.flush()
# decrement the number of bears in the population
Bear.bear_num -= 1
# dont really need to close because Python will do the garbage collection
# for us. but it cannot hurt to be graceful here.
self.logf.close()
def __str__(self):
age = datetime.datetime.now() - self.created
return " name = %s bear (age %s) number = %i (population %i)" % \
(self.name, age, self.my_num,Bear.bear_num)
# add some dynamic aging to the bears
from bear2 import Bear as Bear2
a = Bear2("Yogi")
print(a)
print(a)
you can define a whole bunch of ways that instances behave upon numerical operation
(e.g., __add__
is what gets called when you type instance_1 + instance_2)
__add__(self, other) __sub__(self, other) __mul__(self, other) __div__(self, other) __mod__(self, other) __divmod__(self, other) __pow__(self, other[, modulo]) __lshift__(self, other) __rshift__(self, other) __and__(self, other) __xor__(self, other)
%%file bear1.py
class Bear:
"""
class to show off addition (and multiplication)
"""
bear_num = 0
def __init__(self,name):
self.name = name
print(" made a bear called %s" % (name))
Bear.bear_num += 1
self.my_num = Bear.bear_num
def __add__(self,other):
## spawn a little tike
cub = Bear("progeny_of_%s_and_%s" % (self.name,other.name))
cub.parents = (self,other)
return cub
def __mul__(self,other):
## multiply (as in "go forth and multiply") is really the same as adding
return self.__add__(other)
from bear1 import Bear as Bear1
y = Bear1("Yogi") ; c = Bear1("Fuzzy")
our_kid = y + c
our_kid.
our_kid.parents
our_kid.parents[0].name
our_kid.parents[1].name
y.broken_limb = True
our_kid1 = y * c
__dict__ : Dictionary containing the class's namespace. __doc__ : Class documentation string, or None if undefined. __name__: Class name. __module__: Module name in which the class is defined. This attribute is "__main__" in interactive mode. __bases__ : A possibly empty tuple containing the base classes, in the order of their occurrence in the base class list.
print(Bear1.__doc__)
print(Bear1.__name__)
print(Bear1.__module__)
print(Bear1.__bases__)
print(Bear1.__dict__)
class JustCounter:
__secretCount = 0
x = 0
def count(self):
self.__secretCount += 1
self.x += 1
print(self.__secretCount)
counter = JustCounter()
counter.count() ; counter.count()
print(counter.x)
print(counter.__secretCount)
no attribute is ever precisely private
double underscore attributes are exposed as object._className__attrName
counter._JustCounter__secretCount
a = Bear("Yogi")
a
b = a
b
a.name = "Fuzzy"
b.name
Bear.bear_num
import copy
c = copy.copy(a)
c # new memory location
Bear.bear_num
c.name
c.name = "Smelly"
a.name
a.mylist = [1,2,3]
b.mylist
c.mylist
d = copy.copy(a)
d.mylist
d.name
d.name = "Yogi"
a.name
a.mylist[0] = -1
d.mylist
e = copy.deepcopy(a)
a.__dict__
del a.logf
e = copy.deepcopy(a)
a.mylist[0] = "a"
e.mylist
Bear.bear_num
deepcopy
: copies all attributes pointed to internally
class classname(baseclass):
For example,
class Flower(Plant):
Here we say that "the class Flower is a subclass of the base class Plant." Plant may itself be a subclass of LivingThing
attributes of the baseclass are inherited by the subclass
class Plant:
num_known = 0
def __init__(self,common_name,latin_name=None):
self.latin_name = latin_name
self.common_name = common_name
Plant.num_known += 1
class Flower(Plant):
has_pedals = True
p = Plant("poison ivy")
e = Flower("poppy")
e.has_pedals
Plant.num_known
Flower.__bases__[0].__name__
instantiation of a Flower reuses the __init__
from the Plant class. It also sets has pedals = True
class Plant:
num_known = 0
def __init__(self,common_name,latin_name=None):
self.latin_name = latin_name
self.common_name = common_name
Plant.num_known += 1
def __str__(self):
return "I am a plant (%s)!" % self.common_name
class Flower(Plant):
has_pedals = True
def __str__(self):
return "I am a flower (%s)!" % self.common_name
now the __str__
method of Flower takes precedence over the __str__
method of the parent class
f = Flower("rose") ; print(f)
p = Plant("oak"); print(p)
class Flower(Plant):
has_pedals = True
def __init__(self,common_name,npedals=5,pedal_color="red",latin_name=None):
## call the __init__ of the parent class
Plant.__init__(self,common_name,latin_name=latin_name)
self.npedals = npedals
self.pedal_color = pedal_color
def __str__(self):
return "I am a flower (%s)!" % self.common_name
we can still use the parent class' __init__
f = Flower("rose") ; print(f)
class A:
def __init__(self):
print("A")
class B(A):
def __init__(self):
A.__init__(self)
print("B")
a = A()
b = B()
class Flower1(Plant,EdibleFood,SmellyStuff)
when executing a method the namespace of:
Flower1
is searched firstPlant
second (and it's baseclasses...and their baseclasses)EdibleFood
second (and it's baseclasses...and their baseclasses)SmellyStuff
second (and it's baseclasses...and their baseclasses)3.1415/0
def this_fails():
x = 3.1415/0
try:
this_fails()
except ZeroDivisionError as detail:
print('Handling run-time error:',detail )
import exceptions
http://docs.python.org/library/exceptions.html
exception BaseException exception Exception exception StandardError exception ArithmeticError exception LookupError exception EnvironmentError exception AssertionError exception AttributeError exception EOFError exception GeneratorExit exception IOError exception ImportError exception IndexError exception KeyError exception KeyboardInterrupt exception MemoryError exception NameError exception OverflowError exception ReferenceError exception RuntimeError exception StopIteration exception SyntaxError exception SystemError exception SystemExit exception TypeError exception ValueError exception VMSError exception WindowsError exception ZeroDivisionError exception Warning exception UserWarning exception DeprecationWarning exception PendingDeprecationWarning exception SyntaxWarning exception RuntimeWarning exception FutureWarning exception ImportWarning
def divide(x, y):
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
divide(2,1)
divide(2,0)
divide("2","1")
%%file catcherr.py
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as err:
print("I/O error: %s" % err)
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise
exc_info(...)
exc_info() -> (type, value, traceback)
Return information about the most recent exception caught by an except
clause in the current stack frame or in an older stack frame.
run catcherr
we can raise errors in our codes (which themselves might be caught upstream)
a = "cat food"
if a != "spam":
raise NameError("anything that isn't spam breaks my code")
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StandardError | +-- BufferError | +-- ArithmeticError | | +-- FloatingPointError | | +-- OverflowError | | +-- ZeroDivisionError | +-- AssertionError | +-- AttributeError | +-- EnvironmentError | | +-- IOError | | +-- OSError | | +-- WindowsError (Windows) | | +-- VMSError (VMS) | +-- EOFError | +-- ImportError | +-- LookupError | | +-- IndexError | | +-- KeyError | +-- MemoryError | +-- NameError | | +-- UnboundLocalError | +-- ReferenceError | +-- RuntimeError | | +-- NotImplementedError | +-- SyntaxError | | +-- IndentationError | | +-- TabError | +-- SystemError | +-- TypeError | +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning
import datetime
class MyError(StopIteration):
def __init__(self,value=None):
## call the baseclass Exception __init__
Exception.__init__(self)
self.value = value
print("exception with %s at time %s" % (self.value,datetime.datetime.now()))
def __str__(self):
return "you said %s" % self.value
raise MyError("darnit")
%debug
%pdb