1 Part 1 Beginning Python
1.8 Classes
Classes model the behavior of objects in the "real" world. Methods implement the behaviors of these types of objects. Member variables hold (current) state. Classes enable us to implement new data types in Python.
The class: statement is used to define a class. The class: statement creates a class object and binds it to a name.
1.8.1 A simple class
In [104]: class A:
...: pass ...:
In [105]: a = A()
To define a new style class (recommended), inherit from object or from another class that does. Example:
In [21]: class A(object):
....: pass ....:
In [22]:
In [22]: a = A() In [23]: a
Out[23]: <__main__.A object at 0x82fbfcc>
1.8.2 Defining methods
A method is a function defined in class scope and with first parameter self:
In [106]: class B(object):
...: def show(self):
...: print 'hello from B' ...:
In [107]: b = B() In [108]: b.show() hello from B
A method as we describe it here is more properly called an instance method, in order to distinguish it from class methods and static methods.
1.8.3 The constructor
The constructor is a method named __init__.
Exercise: Define a class with a member variable name and a show method. Use print to show the name. Solution:
In [109]: class A(object):
...: def __init__(self, name):
...: self.name = name ...: def show(self):
...: print 'name: "%s"' % self.name ...:
Notes:
● The self variable is explicit. It references the current object, that is the object whose method is currently executing.
● The spelling ("self") is optional, but everyone spells it that way.
1.8.4 Member variables
Defining member variables Member variables are created with assignment. Example:
class A(object):
def __init__(self, name):
self.name = name
A small gotcha Do this:
In [28]: class A(object):
....: def __init__(self, items=None):
....: if items is None:
....: self.items = []
....: else:
....: self.items = items
Do not do this:
In [29]: class B:
....: def __init__(self, items=[]): # wrong. list ctor evaluated only once.
....: self.items = items
In the second example, the def statement and the list constructor are evaluated only once. Therefore, the item member variable of all instances of class B, will share the same value, which is most likely not what you want.
1.8.5 Calling methods
● Use the instance and the dot operator.
● Calling a method defined in the same class or a superclass:
○ From outside the class Use the instance:
some_object.some_method()
an_array_of_of_objects[1].another_method()
○ From within the same class Use self:
self.a_method()
○ From with a subclass when the method is in the superclass and there is a method with the same name in the current class Use the class (name) or use super:
SomeSuperClass.__init__(self, arg1, arg2) super(CurrentClass,
self).__init__(arg1, arg2)
● Calling a method defined in a specific superclass Use the class (name).
1.8.6 Adding inheritance
Referencing superclasses Use the builtin super or the explicit name of the superclass. Use of super is preferred. For example:
In [39]: class B(A):
....: def __init__(self, name, size):
....: super(B, self).__init__(name)
....: # A.__init__(self, name) # an older alternative form
....: self.size = size
The use of super() may solve problems searching for the base class when using multiple inheritance. A better solution is to not use multiple inheritance.
You can also use multiple inheritance. But, it can cause confusion. For example, in the following, class C inherits from both A and B:
class C(A, B):
...
Python searches superclasses MRO (method resolution order). If only single inheritance is involved, there is little confusion. If multiple inheritance is being used, the search order of super classes can get complex see here:
http://www.python.org/download/releases/2.3/mro
For more information on inheritance, see the tutorial in the standard Python documentation set: 9.5 Inheritance and 9.5.1 Multiple Inheritance.
Watch out for problems with inheriting from multiple classes that have a common base class.
1.8.7 Class variables
● Also called static data.
● A class variable is shared by instances of the class.
● Define at class level with assignment. Example:
class A(object):
size = 5
def get_size(self):
return A.size
● Reference with classname.variable.
● Caution: self.variable = x creates a new member variable.
1.8.8 Class methods and static methods
Instance (plain) methods:
● An instance method receives the instance as its first argument.
Class methods:
● A class method receives the class as its first argument.
● Define class methods with builtin function classmethod() or with decorator
@classmethod.
● See the description of classmethod() builtin function at "Builtin Functions": http://docs.python.org/2/library/functions.html#classmethod Static methods:
● A static method receives neither the instance nor the class as its first argument.
● Define static methods with builtin function staticmethod() or with decorator @staticmethod.
● See the description of staticmethod() builtin function at "Builtin Functions": http://docs.python.org/2/library/functions.html#staticmethod Notes on decorators:
● A decorator of the form @afunc is the same as m = afunc(m). So, this:
@afunc
def m(self): pass
is the same as:
def m(self): pass m = afunc(m)
● You can use decorators @classmethod and @staticmethod (instead of the classmethod() and staticmethod() builtin functions) to declare class methods and static methods.
Example:
class B(object):
Count = 0
def dup_string(x):
s1 = '%s%s' % (x, x,) return s1
dup_string = staticmethod(dup_string) @classmethod
def show_count(cls, msg):
print '%s %d' % (msg, cls.Count, ) def test():
print B.dup_string('abcd')
B.show_count('here is the count: ')
An alternative way to implement "static methods" Use a "plain", modulelevel function. For example:
In [1]: def inc_count():
...: A.count += 1 ...:
In [2]:
In [2]: def dec_count():
...: A.count = 1 ...:
In [3]:
In [3]: class A:
...: count = 0
...: def get_count(self):
...: return A.count ...:
In [4]:
In [4]: a = A()
In [5]: a.get_count() Out[5]: 0
In [6]:
In [6]:
In [6]: inc_count() In [7]: inc_count() In [8]: a.get_count() Out[8]: 2
In [9]:
In [9]: b = A()
In [10]: b.get_count() Out[10]: 2
1.8.9 Properties
The property builtin function enables us to write classes in a way that does not require a user of the class to use getters and setters. Example:
class TestProperty(object):
def __init__(self, description):
self._description = description def _set_description(self, description):
print 'setting description' self._description = description def _get_description(self):
print 'getting description' return self._description
description = property(_get_description, _set_description)
The property builtin function is also a decorator. So, the following is equivalent to the above example:
class TestProperty(object):
def __init__(self, description):
self._description = description @property
def description(self):
print 'getting description' return self._description
@description.setter
def description(self, description):
print 'setting description' self._description = description
Notes:
● We mark the instance variable as private by prefixing it with and underscore.
● The name of the instance variable and the name of the property must be different.
If they are not, we get recursion and an error.
For more information on properties, see Builtin Functions properties
http://docs.python.org/2/library/functions.html#property
1.8.10 Interfaces
In Python, to implement an interface is to implement a method with a specific name and a specific arguments.
"Duck typing" If it walks like a duck and quacks like a duck ...
One way to define an "interface" is to define a class containing methods that have a header and a doc string but no implementation.
Additional notes on interfaces:
● Interfaces are not enforced.
● A class does not have to implement all of an interface.
1.8.11 Newstyle classes
A newstyle class is one that subclasses object or a class that subclasses object (that is, another newstyle class).
You can subclass Python's builtin datatypes.
● A simple example the following class extends the list datatype:
class C(list):
def get_len(self):
return len(self) c = C((11,22,33)) c.get_len()
c = C((11,22,33,44,55,66,77,88)) print c.get_len()
# Prints "8".
● A slightly more complex example the following class extends the dictionary
datatype:
class D(dict):
def __init__(self, data=None, name='no_name'):
if data is None:
data = {}
dict.__init__(self, data) self.name = name
def get_len(self):
return len(self) def get_keys(self):
content = []
for key in self:
content.append(key)
contentstr = ', '.join(content) return contentstr
def get_name(self):
return self.name def test():
d = D({'aa': 111, 'bb':222, 'cc':333}) # Prints "3"
print d.get_len()
# Prints "'aa, cc, bb'"
print d.get_keys() # Prints "no_name"
print d.get_name()
Some things to remember about newstyle classes:
● In order to be newstyle, a class must inherit (directly or indirectly) from
object. Note that if you inherit from a builtin type, you get this automatically.
● Newstyle classes unify types and classes.
● You can subclass (builtin) types such as dict, str, list, file, etc.
● The builtin types now provide factory functions: dict(), str(), int(), file(), etc.
● The builtin types are introspectable Use x.__class__, dir(x.__class__), isinstance(x, list), etc.
● Newstyle classes give you properties and descriptors.
● Newstyle classes enable you to define static methods. Actually, all classes enable you to do this.
● A newstyle class is a userdefined type. For an instance of a newstyle class x, type(x) is the same as x.__class__.
For more on newstyle classes, see: http://www.python.org/doc/newstyle/
Exercises:
● Write a class and a subclass of this class.
○ Give the superclass one member variable, a name, which can be entered when
an instance is constructed.
○ Give the subclass one member variable, a description; the subclass constructor should allow entry of both name and description.
○ Put a show() method in the superclass and override the show() method in the subclass.
Solution:
class A(object):
def __init__(self, name):
self.name = name def show(self):
print 'name: %s' % (self.name, ) class B(A):
def __init__(self, name, desc):
A.__init__(self, name) self.desc = desc
def show(self):
A.show(self)
print 'desc: %s' % (self.desc, )
1.8.12 Doc strings for classes
Add docstrings as a (triplequoted) string beginning with the first line of a class. See epydoc for a suggested format.
1.8.13 Private members
Add an leading underscore to a member name (method or data variable) to "suggest" that the member is private.