Dies ist die Support Website des Buches:
Das Python Praxisbuch
Der große Profi-Leitfaden für Programmierer
Farid Hajji
Addison Wesley / Pearson Education
ISBN 978-3-8273-2543-3 (Sep 2008), 1298 Seiten.
10. Klassen und Objekte¶
Hello, OO-World!¶
#!/usr/bin/env python
# helloooworld.py -- Hello, OO-World!
class Hello(object):
"Hello, OO-world!"
def __init__(self, welcome):
"Squirrel the welcome message away"
self.welcome = welcome
def hello(self):
"Print the saved welcome message"
print self.welcome
def main():
"Play around with Hello"
# Instantiate two Hello objects:
hel1 = Hello("Hello, World!")
hel2 = Hello("Good Bye, Cruel World!")
# Call hel1 and hel2's hello method:
hel1.hello()
hel2.hello()
if __name__ == '__main__':
main()
Klassen verwenden¶
Objekte instanziieren¶
Die leere Klasse C
:
class C(object):
pass
Die Klasse C2
::
class C2(object):
def __init__(self, magic):
self.magic = magic
Objektattribute¶
Objektmethoden (Memberfunktionen)¶
Die Klasse C3
:
class C3(object):
def __init__(self):
self.counter = 0
def inc(self):
self.counter = self.counter + 1
Die Klasse C4
:
class C4(object):
def __init__(self, initvalue=0):
self.counter = initvalue
def inc(self, increment=1):
self.counter = self.counter + increment
Und die Klasse C5
:
class C5(object):
def __init__(self, initvalue=0):
self.counter = initvalue
def add(self, value):
self.counter = self.counter + value
def inc(self):
self.add(1) # Call another method
Klassen schreiben¶
#!/usr/bin/env python
# classdef.py -- Defining classes
class ObjectCounter(object):
"A class that counts how many objects it created."
nr_objects = 0
def __init__(self, value=''):
"Create a new object. Count it!"
ObjectCounter.nr_objects = ObjectCounter.nr_objects + 1
self.value = value
def get_value(self):
"Get the value of this object"
return self.value
def set_value(self, newvalue):
"Change the value of this object"
self.value = newvalue
def object_count(self):
"Return the number of ObjectCounter objects created so far."
return ObjectCounter.nr_objects
# This is a class method
def override_object_count_cmethod(cls, newcount):
print "Overriding %s.%d with %d" % (cls, cls.nr_objects, newcount)
cls.nr_objects = newcount
override_object_count_cmethod = classmethod(override_object_count_cmethod)
# This is a static method
def override_object_count_static(newcount):
print "Overriding object count %d with %d" % (ObjectCounter.nr_objects,
newcount)
ObjectCounter.nr_objects = newcount
override_object_count_static = staticmethod(override_object_count_static)
Klassen aus Modulen importieren:
# 1. Either import just the names we want:
from classdef import ObjectCounter
obj_1 = ObjectCounter()
obj_1.get_value()
# 2. Or import the whole module:
import classdef
obj_1 = classdef.ObjectCounter(42)
obj_2 = classdef.ObjectCounter('hello')
obj_1.get_value()
obj_2.set_value(4711)
Klassenmethoden und statische Methoden¶
Die Klasse ObjectCounter
mit classmethod
:
class ObjectCounter(object):
nr_objects = 0
# Regular member functions omitted
# This is a class method
def override_object_count_cmethod(cls, newcount):
print "Overriding %s.%d with %d" % (cls, cls.nr_objects, newcount)
cls.nr_objects = newcount
override_object_count_cmethod = classmethod(override_object_count_cmethod)
Eine weiterer ObjectCounter
mit staticmethod
:
class ObjectCounter(object):
nr_objects = 0
# Regular member functions omitted
# This is a static method
def override_object_count_static(newcount):
print "Overriding object count %d with %d" % (ObjectCounter.nr_objects,
newcount)
ObjectCounter.nr_objects = newcount
override_object_count_static = staticmethod(override_object_count_static)
Klassenvererbung¶
Die Klassen Widget
und Window
:
class Widget(object):
"A generic widget class"
def __init__(self, value=''):
self.value = value
def get_value(self):
return self.value
class Window(Widget):
"A Window is a special Widget"
def __init__(self):
Widget.__init__(self, 'TheWindow')
Die Klasse Dialog
:
class Dialog(Widget):
"A Dialog is a special Widget"
def __init__(self):
super(Dialog, self).__init__('This is a Dialog')
Hooks¶
Ein Einführung in Hooks¶
Die Klasse object2
:
class object2(object):
def __str__(self):
"Show object2 in a custom manner"
return 'object2(0x%x)' % id(self)
Eine Tour der object-Hooks¶
#!/usr/bin/env python
# objecthooks.py -- instrument the class object by intercepting some hooks.
class object_i(object):
'''An object with instrumented hooks.'''
# __doc__ is a documentation string for the whole class
__doc__ == 'An instrumented object'
# __new__ is a class method for creating new instances
def __new__(cls, *args, **kwargs):
print "CALLED object_i.__new__(%s, %s, %s)" \
% (cls, str(args), str(kwargs))
return object.__new__(cls, args, kwargs)
# The initializer (constructor)
def __init__(self):
print "CALLED object_i.__init__()"
return super(object_i, self).__init__()
# Called for del self.attrname
def __delattr__(self, attrname):
print "CALLED object_i.__delattr__(%s)" % (attrname,)
return super(object_i, self).__delattr__(attrname)
# Called for self.attrname
def __getattribute__(self, attrname):
print "CALLED object_i.__getattribute__(%s)" % (attrname,)
return super(object_i, self).__getattribute__(attrname)
# Called for self.attrname = attrvalue
def __setattr__(self, attrname, attrvalue):
print "CALLED object_i.__setattr__(%s, %s)" % (attrname, attrvalue)
return super(object_i, self).__setattr__(attrname, attrvalue)
# Called for str(self)
def __str__(self):
print "CALLED object_i.__str__()"
return 'object_i(0x%x)' % (id(self),)
# Called for repr(self)
def __repr__(self):
print "CALLED object_i.__repr__()"
return '<repr: object_i at 0x%x>' % (id(self),)
# Called for hash(self)
def __hash__(self):
print "CALLED object_i.__hash__()"
return super(object_i, self).__hash__()
Ein Dictionary mit case-insensitive Schlüsseln¶
#!/usr/bin/env python
# dictci.py -- dictionary with case-insensitive (string) keys.
class dictci(dict):
'''Dictionary with case-insensitive (string) keys.'''
__doc__ == 'A case insensitive dictionary'
def __init__(self, mapping={}, *seq, **kwargs):
for key, value in mapping.items():
self.__setitem__(key.lower(), value)
for key, value in seq:
self.__setitem__(key.lower(), value)
for key, value in kwargs.items():
self.__setitem__(key.lower(), value)
def __contains__(self, key):
return super(dictci, self).__contains__(key.lower())
def __delitem__(self, key):
return super(dictci, self).__delitem__(key.lower())
def __getitem__(self, key):
return super(dictci, self).__getitem__(key.lower())
def __setitem__(self, key, value):
return super(dictci, self).__setitem__(key.lower(), value)
Ein Dictionary mit Default-Werten¶
#!/usr/bin/env python
# dictdefault.py -- dictionary with default value
class dictdefault(dict):
'''Dictionary with default value.'''
__doc__ == 'A dictionary with default value'
def __init__(self, default=None, mapping={}, *seq, **kwargs):
self.default = default
for key, value in mapping.items():
self.__setitem__(key, value)
for key, value in seq:
self.__setitem__(key, value)
for key, value in kwargs.items():
self.__setitem__(key, value)
def __contains__(self, key):
return True # Every imaginable keys is there with default value!
def __getitem__(self, key):
try:
return super(dictdefault, self).__getitem__(key)
except KeyError:
return self.default
Ein aufrufbares Objekt¶
Die Klassen TheAnswer
und TheAdder
:
class TheAnswer(object):
def __call__(self):
return 42
class TheAdder(object):
def __call__(self, *args):
return sum(args)
Die Klasse Counter
:
class Counter(object):
def __init__(self, start=0):
self.start = start
def __call__(self):
self.start = self.start + 1
return self.start
Propertys¶
#!/usr/bin/env python
# properties.py -- how to define properties.
class MyClass(object):
def __init__(self, initval=0):
print "Object created at 0x%x" % id(self)
self._x = initval
def getter(self):
print "getter(0x%x) called" % id(self)
return self._x
def setter(self, value):
print "setter(0x%x, %d) called" % (id(self), value)
self._x = value
def deleter(self):
print "deleter(0x%x) called" % id(self)
del self._x
x = property(getter, setter, deleter, "I'm a managed attribute")
#!/usr/bin/env python
# posint.py -- positive integers implemented as a property
class PosInt(object):
"A positive integer"
class InvalidValue(Exception):
pass
def __init__(self, i):
if i <= 0:
raise PosInt.InvalidValue("Only positive integers allowed")
self._i = i
def getter(self):
return self._i
def setter(self, value):
if value <= 0:
raise PosInt.InvalidValue("Only positive integers allowed")
self._i = value
def deleter(self):
del self._i
x = property(getter, setter, deleter, "A positive integer property")
Deskriptoren¶
Die Klasse TimeDescriptor
:
import time
class TimeDescriptor(object):
def __get__(self, instance, owner):
return time.time()
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass
Die Klasse TimeDemo
:
class TimeDemo(object):
thetime = TimeDescriptor()
def __init__(self, somevalue):
self.data = somevalue
#!/usr/bin/env python
# chattydescriptor.py -- A verbose descriptor class.
class ChattyDescriptor(object):
"A chatty descriptor class"
def __init__(self):
self.store = {}
def __get__(self, instance, owner):
print "CALLED __get__(%s, %s, %s)" % \
(str(self), str(instance), str(owner))
try:
value = self.store[instance]
self.store[instance] = value + 1
return value
except KeyError:
raise AttributeError("There is no such attribute")
def __set__(self, instance, value):
print "CALLED __set__(%s, %s, %s)" % \
(str(self), str(instance), str(value))
self.store[instance] = value
def __delete__(self, instance):
print "CALLED __delete__(%s, %s)" % \
(str(self), str(instance))
del self.store[instance]
def keyhole(self):
return self.store
Die Klasse ChattyDescriptorDemo
:
class ChattyDescriptorDemo(object):
"An example owner class for ChattyDescriptor"
x = xmanager
__slots__¶
Das Problem:
alist = []
for i in range(1000):
o = ChattyDescriptorDemo()
o.x = "Object number %d" % (i,)
alist.append(o)
Die Klasse RGB
:
class RGB(object):
def __init__(self, red, green, blue):
self.red = red
self.green = green
self.blue = blue
Die Klasse RGB2
:
class RGB2(object):
__slots__ = ['red', 'green', 'blue']
def __init__(self, r, g, b):
self.red = r
self.green = g
self.blue = b
Metaklassen¶
Klassen sind Instanzen von Metaklassen¶
Die Klasse MyClass
:
class MyClass(object):
def __init__(self, initval=0):
self.data = initval
def show(self):
print self.data
Die Klasse MyClass2
erzeugen:
def __init__(self, initval=0):
self.data = initval
def show(self):
print self.data
MyClass2 = type('MyClass2', (object,),
{'__init__': __init__, 'show': show})
Die Metaklasse ChattyMetaClass
:
class ChattyMetaClass(type):
"A verbose meta class"
def __new__(meta, name, bases, dict):
print "ChattyMetaClass(%s, %s, %s)" % (name, str(bases), str(dict))
return type.__new__(meta, name, bases, dict)
Daraus die Klasse MyClass3
erzeugen:
>>> MyClass3 = ChattyMetaClass('MyClass3', (object,),
... {'__init__': __init__, 'show': show})
ChattyMetaClass(MyClass3, (<type 'object'>,),
{'__init__': <function __init__ at 0x284187d4>,
'show': <function show at 0x2841880c>})
Die Metaklasse MetaClassFactory
:
def MetaClassFactory(name, bases, dict):
"A factory function that cranks out classes"
print "CALLED MetaClassFactory(%s, %s, %s)" % \
(name, str(bases), str(dict))
return type(name, bases, dict)
Draus die Klasse MyClass4
erzeugen:
>>> MyClass4 = MetaClassFactory('MyClass4', (object,),
... {'__init__': __init__, 'show': show})
CALLED MetaClassFactory(MyClass4, (<type 'object'>,),
{'__init__': <function __init__ at 0x284187d4>,
'show': <function show at 0x2841880c>})
Das __metaclass__-Attribut¶
Die Klasse MyClass5
:
class MyClass5(object):
"A class created from a custom meta class"
__metaclass__ = ChattyMetaClass
def __init__(self, initvalue=0):
self.data = initvalue
def show(self):
print self.data
Die Klasse MyClass6
:
class MyClass6(object):
"A class created from a custom class factory"
__metaclass__ = MetaClassFactory
def __init__(self, initvalue=0):
self.data = initvalue
def show(self):
print self.data
Die Klasse MyDerivedClass
:
class MyDerivedClass(MyClass5):
def show(self):
print "derived",
super(MyDerivedClass, self).show()
Anwendungen von Metaklassen¶
Klassen umbenennen¶
Die Metaklasse RenameMetaClass
:
class RenameMetaClass(type):
"A meta class that renames classes by prepending a prefix"
def __new__(meta, name, bases, dict):
return type.__new__(meta, 'My' + name, bases, dict)
Die Klassen A
und B
:
class A(object):
__metaclass__ = RenameMetaClass
class B(object):
__metaclass__ = RenameMetaClass
Die Klasse D
:
class D(A, B):
pass
Mixin-Klassen als Metaklassen¶
Die Mixin-Klasse MyMixin
:
class MyMixin:
def foo(self):
print "foo() from Mixin:", self.fooval
def bar(self):
print "bar() from Mixin:", self.barval
Die Klasse MyClass
:
class MyClass(object, MyMixin):
def __init__(self, fooval, barval):
self.fooval = fooval
self.barval = barval
def foobar(self):
print "foobar() from MyClass:", self.fooval, self.barval
Es geht auch so:
def foometa(self):
print "foo() from Metamixin:", self.fooval
def barmeta(self):
print "bar() from Metamixin:", self.barval
class MyMetaMixin(type):
def __new__(meta, name, bases, dict):
dict.update({'foo': foometa, 'bar': barmeta})
return type.__new__(meta, name, bases, dict)
Daraus erzeugen wir MyClass2
:
class MyClass2(object):
__metaclass__ = MyMetaMixin
def __init__(self, fooval, barval):
self.fooval = fooval
self.barval = barval
def foobar(self):
print "foobar() from MyClass2:", self.fooval, self.barval