An introduction to python classes
#class_examples.py
#
#Theses examples were used in a talk I
#gave at the BangPipers meeting on
#16/04/2005
#Starting with an empty class
class Greeter(object):
pass
#Lets add a simple method
def meth(self):
print "this is a method of class ", self.__class__
simpleobject = Greeter()
Greeter.meth = meth
simpleobject.meth()
Greeter.meth(simpleobject)
#Prints:
#this is a method of class <class '__main__.Greeter'>
#An init method for our greeter class
def init(self, text):
self.text = text
Greeter.__init__ = init
greeting = Greeter("Greetings from the great beyond")
print greeting.text
#Prints:
#Greetings from the great beyond
#Adding a greet method to print the greeting text
def greet(self):
print self.text
Greeter.greet = greet
greeting.greet()
#Prints:
#Greetings from the great beyond
#Now lets inherit from Greeter to create
#a Hello greeting
class Hello(Greeter):
def __init__(self):
self.text = "Hello"
hello = Hello()
hello.greet()
#Prints:
#Hello
#Overloading __new__ to control instance creation
#__new__ gets called before __init__ during
#instance creation.
#FussyGreeter will return an insult object if
#os.platform is not "win32"
class FussyGreeter(Greeter):
acceptedPlatform = "win32"
def __new__(cls, greeting):
import sys
if cls.acceptedPlatform != sys.platform:
class Insult(object):
def greet(self):
print "You call that an OS?!? Get a real one like", cls.acceptedPlatform
return Insult()
else:
return Greeter.__new__(cls)
greet = FussyGreeter("Howdy")
greet.greet()
#Prints:
#Howdy
FussyGreeter.acceptedPlatform = "linux"
greet = FussyGreeter("Howdy")
greet.greet()
#Prints:
#You call that an OS?!? Get a real one like linux
print type(greet)
#Prints:
#<class '__main__.Insult'>
#Checking call order for __new__ and __init__
#Note:If __new__ returns anything other than an obect
#of type SimpleClass, __init__ will not be called.
class SimpleClass(object):
def __init__(self):
print "calling __init__(%s)"%self
def __new__(cls):
print "calling __new__(%s)"%cls
return object.__new__(SimpleClass)
simpleobject = SimpleClass()
#Prints:
#calling __new__(<class '__main__.SimpleClass'>)
#calling __init__(<__main__.SimpleClass object at 0x011AB650>)
#Here is a simple example of operator overloading
#We overload the '*' operator.
def mul(self, count):
text = self.text
if text[-1] == "s":
endString = ""
else:
endString = "s"
return Greeter("%i %s" % (count, text) + endString)
Greeter.__mul__ = mul
doubleHello = hello * 2
doubleHello.greet()
#Prints:
#2 Hellos
print doubleHello
#Prints:
#<__main__.Greeter object at 0x011AB330>
#We can write an __str__ method to control
#what gets printed
def str_(self):
return self.text
Greeter.__str__ = str_
print doubleHello
#Prints:
#2 Hellos
#multiple inheritence
#mro
#super
class A(object):
def f(self):
print "A.f(inst)"
class B(A):
def f(self):
print "B.f(inst)"
super(B, self).f()
class C(A):
def f(self):
print "C.f(inst)"
super(C, self).f()
class D(B, C):
def f(self):
print "D.f(inst)"
super(D, self).f()
d = D()
print d.__class__.mro();
#Prints:
#[<class '__main__.D'>, <class '__main__.B'>,
#<class '__main__.C'>, <class '__main__.A'>, <type 'object'>]
d.f()
#Prints:
#D.f(inst)
#B.f(inst)
#C.f(inst)
#A.f(inst)
#We can control attribute access for an
#object by overriding the methods
#__getattr__ and __setattr__
class attrdict(dict):
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
self[name] = value
d = attrdict()
d.a = 4
#Same as d.__setattr__("a", 4)
print d.a
#Same as print d.__getattr__("a")
#__getattr__ only gets called if python is
#unable to find the attribute name withen the object
#and its class
#This means that if I assign an attribute with the same name
#as one in dict
d.fromkeys = "hello"
#I wont be able to access the value
print d.fromkeys
#Prints:
#<built-in method fromkeys of type object at 0x01217828>
#We need to overload __getattribute__ to get complete controll
#over attribute lookup
def getattribute(self, name):
return dict.__getitem__(self, name)
attrdict.__getattribute__ = getattribute
print d.fromkeys
#Prints:
#hello
#__slots__
#Class magic
#Classes in python are code objects that get executed when
#they are loaded.
#Lest look at some examples
class HelloWorld:
print "hello world"
#Prints:
#hello world
#Something illegal
class ManyVars:
for i in range(26):
locals()[chr(i+97)] = i
print dir(ManyVars)
#Prints:
#['__doc__', '__module__', 'a', 'b', 'c', 'd', 'e',
#'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
#'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
#'y', 'z']
#Legal using exec
class ManyVars:
for i in range(26):
exec "%s = %i" % (chr(i+97), i)
print dir(ManyVars)
#Prints:
#['__doc__', '__module__', 'a', 'b', 'c', 'd', 'e',
#'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
#'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
#'y', 'z']
#Metaclasses
#Meta classes are class constructors
#A meta class must accept a classname,
#a tuple of base classes and a dictionary
#of name value pairs representing the
#class's attributes and their values.
#Lets create a simple class and extract
#all its local name bindings into a global
#variable called l
class C:
def __init__(self):
self.text = "Namaste"
global l
l = locals()
print l
#Prints:
#{'__module__': '__main__', '__doc__': None,
#'__init__': <function __init__ at 0x011E03B0>}
#We can use type as a class constructor to
#construct a class called Namaste which is
#a subclass of Greeter and contains attributes
#defined in l
Namaste = type("Namaste", (Greeter,), l)
namaste = Namaste()
namaste.greet()
#Prints:
#Namaste
#Lets create a simple empty class
SimpleClass = type("SimpleClass", (), {})
simpleInstance = SimpleClass()
print simpleInstance
#Prints:
#<__main__.SimpleClass object at 0x011DE2F0>
#Metaclasses are the same as other classes
#What makes them special is that they are
#all subclasses of type
#Lets look at the call order of the __new__ and __init__
#methods of a simple metaclass
class PrintingMetaclass(type):
def __init__(self, name, bases, dct):
print "calling __init__"
return type.__init__(self, name, bases, dct)
def __new__(cls, name, bases, dct):
print "calling __new__"
return type.__new__(cls, name, bases, dct)
SimpleClass = PrintingMetaclass("SimpleClass", (), {})
#Prints:
#calling __new__
#calling __init__
#We can also set the metaclass for a particular
#clas int using the class attribute __metaclass__
class SimpleClass:
__metaclass__ = PrintingMetaclass
#Prints:
#calling __new__
#calling __init__
#Here's an example of metaclasses in action
_securityNumbers = [1,2,3]
class SecurityMetaclass(type):
def __new__(self, name, bases, dct):
import types
for (name, value) in dct.items():
if isinstance(value, types.FunctionType):
def func(self, securityNumber, *args, **kwargs):
if securityNumber in _securityNumbers:
return value(self, *args, **kwargs)
else:
raise Exception, "You are not authorized to call this method"
dct[name] = func
print dct
return type.__new__(self, name, bases, dct)
class SecureClass(object):
__metaclass__ = SecurityMetaclass
def display(self, value):
print value
secureObject = SecureClass()
secureObject.display(1, "This is a secret message.")
#Prints:
#This is a secret message.
#secureObject.display(7, "This is a secret message.")
#Will throw an exception
#Descriptors
#__get__(self, obj, type)
#__set__(self, obj, value)
#__delete__(self, obj)
#Lets create a class to work with
class DiscrExp(object):pass
inst = DiscrExp()
#Here is a simple example of properties
#in python
def fset(self, value):
self.value = value*2
def fget(self):
return self.value
DiscrExp.doublingValue = property(fget, fset)
inst.doublingValue = 2
print inst.doublingValue
#Prints:
#4
#Lets create a printing discriptor to see how
#the different methods of a descriptor are
#called
class PrintingDiscriptor(object):
def __get__(self, obj, type):
print "__get__"
print "obj = ", obj
print "type = ", type
def __set__(self, obj, value):
print "__set__"
print "obj=", obj
print "value=", value
def __delete__(self, obj):
print "__delete__"
print "obj=",obj
DiscrExp.pd = PrintingDiscriptor()
inst.pd
#Prints:
#__get__
#obj = <__main__.DiscrExp object at 0x011AB890>
#type = <class '__main__.DiscrExp'>
inst.pd = 5
#Prints:
#__set__
#obj= <__main__.DiscrExp object at 0x011AB890>
#value= 5
DiscrExp.pd
#Prints:
#__get__
#obj = None
#type = <class '__main__.DiscrExp'>
#Creating a static method descriptor
class StaticMethod(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, type):
return self.f
def warning():
print "This is a universal warning, for this class only"
DiscrExp.warning = staticmethod(warning)
DiscrExp.warning()
#Prints:
#This is a universal warning, for this class only
inst.warning()
#Prints:
#This is a universal warning, for this class only
#References:
#http://www.python.org/2.2.3/descrintro.html
#http://users.rcn.com/python/download/Descriptor.htm
#Python in a nutshell 2nd ed.
0 Comments:
Post a Comment
<< Home