PEP 487 oder die Anpassung der Klassenerstellung

Dieses Feature ist ab Python 3.6 verfügbar.

Mit dem Entwurf zu pep487 von Martin Teichmann vom 27 Februar 2015 wurde unter anderem eine Vereinfachung der Klassenestellung unter Python 3 genauer gesagt Python 3.6 vorgesetllt. Im Grundsatz nimmt sich dieser Entwurf der Thematik an, das das Anpassen bei der Klassenerstellung die Verwendung einer benutzerdefinierten Metaklasse erfordert. Diese benutzerdefinierte Metaklasse bleibt aber dann für den gesamten Lebenszyklus der Klasse bestehen, wodurch Metaklassenkonflikte entstehen können.

Hauptvorteile

In der Vergangenheit war es also notwendig auf Metaklassen zurück zu greifen wenn es darum ging bei der Instanziierung von Klassen ein zu greifen. So zum Beispeil beim prüfen ob eine Klasse eine Methode implementiert hat.

Stellen wir uns vor das wir keinen Einfluss darauf haben wie unsere API implementiert wird, aber sicherstellen wollen das bestimmte Methoden implementiert werden. So würde die Umsetzungmittels einer Metaklasse funktionieren.

examples/pep-487/meta_class/sub_class_meta.py (Source)

class BaseMeta(type):

    def __new__(cls, name, bases, body):
        if 'to_json' not in body:
            raise TypeError("Bad Class you are missing something")
        return super().__new__(cls, name, bases, body)


class Base(metaclass=BaseMeta):
    def to_json():
        return "bar"

Äquivalent dazu würden wir dieses Verhalten mit der Hilfe von __init__subclass__ lösen. Ein wichtiges Detail ist hierbei aber das bei der Lösung mittels Metaklassen den TypeError erst raisen würden sobald wir eine Instanz der Klasse Base erstellen. Anders wird bei der Verwendung __init__subclass__ die Evaluierung bereits beim import der erbenden Klasse passieren.

examples/pep-487/meta_class/init_subclass.py (Source)

class PluginBase(object):

    # this is a classmethod
    def __init_subclass__(cls, **kwargs):
        if hasattr(cls, 'to_json'):
            super().__init_subclass__(**kwargs)
        else:
            raise TypeError("Bad Class you are missing something")

Eine Idee die sich daraus ergibt wäre die Implementierung eines einfachen Plugin Systems.

examples/pep-487/plugins/plugin_base.py (Source)

class PluginBase:

    registry = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.registry.append(cls)
examples/pep-487/plugins/custom_plugin.py (Source)
from plugins.plugin_base import PluginBase


class A(PluginBase):
    def to_json(self):
        pass


class B(PluginBase):
    def to_json(self):
        pass
    
examples/pep-487/plugins/__init__.py (Source)
from plugins.custom_plugin import * # noqa
examples/pep-487/main.py (Source)
from plugins.plugin_base import PluginBase # noqa

# now PluginBase.registry contains modules
# [plugins.custom_plugin.A, plugins.custom_plugin.B, ]

Um Metaklassen zu verstehen ist ein tieferes Verständniss von Typensystem innerhlab von Python Notwendig. Ich werde in meinem nächsten Beitrag auf die Verwendung von Metaklassen eingehen.

Derweil kann ich diesen Link zum Thema Metaklassen empfehlen. https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

Viel Spass

restart

Lange hat diese Domain eine statische Seite geziert mit dem Vermerk das ich nicht schreiben will. Beziehungsweise, das keine Zeit vorhanden ist, dass wird sich nun ändern. Aktuell habe ich viele Themen über die es sich zu schreiben lohnt.

##Aktuelle Themen

  • IPDB
  • Django und Cellery
  • PyTest
  • Meta Klassen
  • API Design
  • Django REST Framework
  • Python Allgemein
  • Pandas
  • Numpy

Nach vielen Jahren als Freiberufler möchte ich mich nun mehr meiner Passion widmen und mich noch tiefer spezialisieren, bzw. mein Wissen hier teilen. Bevor es aber richtig los geht muss ich diesen Static Site Generator ( https://getnikola.com ) noch etwas modifizieren und ein par Einstellungen vornehmen.