theme | class | lineNumbers | info | layout | image |
---|---|---|---|---|---|
apple-basic |
text-center |
true |
Class in Python
|
intro-image |
Python Basics - class and exceptions
Class is an abstraction of things. It is one of the key elements of Object-oriented programming (OOP).
class Example:
...
class Example:
"""Example is an example class and shows simple class defnition in Python"""
i = 100
def f(self):
return 100
You can use Example.i
or Example.f
to reference a property.
__doc__
is also a valid attribute, try accessing Example.__doc__
yourself.
In python, you can create a instance by:
example_object = Example()
example_object.i # accessing the attribute
Data variables in class defition are shared data.
Each instance of the class will have a copy of the shared data.
It works expectly most of the time, but sometime it doesn't.
class A:
items = []
a, b = A(), A()
a.items.append('hello')
print(b.items)
The __init__
method (if provided) is called an object is created.
It can be used to set attributes of an object.
class Complex:
def __init__(self, re, im):
self.re = re
self.im = im
Setting attributes of object outside __init__
function is also allowed.
c = Complex()
# set attribute that defined in __init__
c.re = 100
# set new attribute is allowed
c.new_attr = 'this is a new attribute'
A function can be called by obj.func
.
class Complex:
def __init__(self, re, im):
self.re = re
self.im = im
def show(self):
print("Re:", self.re)
print("Im:", self.im)
c = Complex(10, 5)
c.show()
The instance c
is passed as the first argument of the function.
It is equivalent to:
Complex.show(c)
Unlike C++
, you cannot invoke double
function by typing double()
.
Instead, you should use self.double()
class Complex:
def __init__(self, re, im):
self.re = re
self.im = im
def show(self):
print("Re:", self.re)
print("Im:", self.im)
def show_if_not_zero(self):
if self.re == 0 and self.im == 0:
print("It is zero!")
return
self.show()
c = Complex(10, 5)
c.show()
Inherit makes class much more powerful.
class DerivedClassName(BaseClassName):
...
class DerivedClassName(modname.BaseClassName):
...
Instantiation of derived class is the same as a normal class: DerivedClassName()
.
Derived class can override methods defined in base class. For C++ programmers, all methods in Python are effectively virtual
.
class Base:
def __init__(self):
self.what()
def what(self):
print("Hello from base")
class Derived(Base):
def what(self):
print("Hello from derived")
Now Hello from derived
is printed when instantiation.
If you want to explicitly call the method defined in Base:
d = Derived()
Base.what(d)
A funny property: __class__
, it shows the class name of an object
Built-in functions work with inheritance:
isinstance()
checks an instance's type:isinstance(obj, int)
will beTrue
ifobj.__class__
isint
or some class derived fromint
issubclass()
checks class inheritance:issubclass(bool, int)
isTrue
sincebool
is a subclass ofint
class DerivedClassName(Base1, Base2, Base3): ...
When calling DerivedClassName().method_name
, Python will search method_name
accroding to Method Resolution Order(MRO).
In the example above, Base1 and its parents are searched before Base2 and Base3 (like dfs
).
Methods defined in derived class can be overrided by methods defined in base class. We can use private variables.
It is a convention to name private varibales with _
.
However, it is just a convention, the derived class can override this by defining variable with the same name.
Although Python does not support private variable, python will rename all variable prefixed with __
(double underscore) with _className__varname
.
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
...
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
for item in zip(keys, values):
self.items_list.append(item)
for
loop is equivalent to:
- Get the generator with
iter()
function - Use
next()
function to get the next element for iterating - The
next()
function raiseStopIteration
exception, thefor
loop stops
We can implement __iter__
and __next__
function support this.
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
The example mentioned before may be too complex. To define a generator, we can use yield
keyword.
def reversedata):
for index in range(len(data)-1, -1, -1):
yield data[index]
Each time next()
is called on it, the generator resumes where it left off. It remembers all the data values and which statement was last executed.
Its behavior is the same as Reverse
class.
>>> for char in reverse('golf'):
... print(char)
...
f
l
o
g
The StopIteration
will be automatically generated when there is no elements.
Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of square brackets.
sum(i ** 2 for i in range(10))
# dot product
a = [1, 2, 3]
b = [4, 5, 6]
sum(x * y for x, y in zip(a, b))
Actually it can be used for generating list
and dict
.
one_to_ten = [i + 1 for i in range(10)]
Python provides try ... except ...
syntax for handling Exceptions
.
while True:
try:
x = int(input("Please enter a number: "))
break
except ValueError:
print("0ops! This was no valid number. Try again...")
You can handle different Exception
in different block.
while True:
try:
x = int(input("Please enter a number: "))
break
except ValueError:
print("0ops! This was no valid number. Try again...")
except KeyboardInterrupt:
pritn("OK...stopping")
break
Most of the exceptions are inheritted from BaseException
class.
You can customize your own exception by creating a subclass of an existing exception class.
class B(Exception): ...
class C(B): ...
class D(C): ...
for cls in [B, C, D]:
try:
raise cls()
except D:
print("D")
except C:
print("C")
except B:
print("B"))
raise
keyword is used to throw an exception.except
works sequencially.print("B")
will be executed three times if we putexcept B
first.
An optional else
statement can be used for statements that should execute after try
block raised an exception.
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
An optional finally
statement can be used for statements that always executes.