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! ================ .. literalinclude:: ../att/classes/helloooworld.py `helloooworld.py `_ 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 ================= .. literalinclude:: ../att/classes/classdef.py `classdef.py `_ 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 -------------------------- .. literalinclude:: ../att/classes/objecthooks.py `objecthooks.py `_ Ein Dictionary mit case-insensitive Schlüsseln ---------------------------------------------- .. literalinclude:: ../att/classes/dictci.py `dictci.py `_ Ein Dictionary mit Default-Werten --------------------------------- .. literalinclude:: ../att/classes/dictdefault.py `dictdefault.py `_ 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 --------- .. literalinclude:: ../att/classes/properties.py `properties.py `_ .. literalinclude:: ../att/classes/posint.py `posint.py `_ 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 .. literalinclude:: ../att/classes/chattydescriptor.py `chattydescriptor.py `_ 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, (,), {'__init__': , 'show': }) 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, (,), {'__init__': , 'show': }) 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 Weitere Anwendungen von Metaklassen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Zusammenfassung ===============