Article - Savannah

Werbung
Veranschaulichung des
doppelhierarchischen Ansatzes von
CYBOP durch die
Programmiersprache Python
Max Brauer
<[email protected]>
5. September 2012
Abstract
Cybernetics Oriented Programming (CYBOP) stellt den Versuch dar, Lösungen aus der
menschlichen Denkens- und Verhaltensweise in die Programmierung einieÿen zu lassen.
Dieser Ansatz hat sich bereits in nahezu allen anderen Wissenschaftsbereichen durchgesetzt. Lediglich in der Programmierung ist der Mensch den Gegebenheiten der Maschienen
unterworfen. Gemündet ist dieses Vorhaben in der XML-basierten Programmiersprache
CYBOL und dem Interpreter CYBOI[1].
Die vorliegende Arbeit versucht den Ansatz der in CYBOP genutzten Doppelhierarchie[2,
7.3.3 Double Hierarchy, Seite 235] auf die Programmiersprache Python zu übertragen, um
so die Vorteile dieses Vorgehens zu verdeutlichen und Entwicklern den Einstieg in CYBOL
zu erleichtern.
Inhaltsverzeichnis
3.2
Weitergehende
Meta-
Programmierung in Python
1
Einleitung
1
2
CYBOPS Doppelhierarchie
2
3.3
4
2.1
Modelles . . . . . . . . . . . .
2
2.2
Schema
3
2.3
Die
. . . . . . . . . . . .
Doppelhierarchie
Zusammenfassung
6
7
8
9
1 Einleitung
und
deren praktischer Nutzen . . .
Warum Metaprogrammierung?
Literatur
Herleitung des hierarchischen
.
3
Schon seit vielen tausend Jahren beobachtet
3
Darstellung mittels Python
3.1
Der
4
der Mensch die Natur und versucht das da-
doppelthierarchische
Ansatz in Python . . . . . . .
raus resultierende Wissen auf den täglichen
5
Gebrauch zu adaptieren. Ein Beispiel für
1
2 CYBOPS Doppelhierarchie
eine solche Adaption ist das Einsetzen des
Lotuseektes: Dank Nanopartikeln ist es
möglich eine Oberäche so zu gestalten,
Eine essenzielle Erkenntnis der Forschun-
das keine Schmutzpartikel an ihr haften
gen
bleiben.[3]
von
alles
die,
dass
beinhaltet.
ten Räume mit Büchern. Die Bücher en-
gramming im Kapitel 5 Extended Moti-
thalten Kapitel, welche Absätze enthalten.
vation mit folgenden Worten:
Diese wiederum enthalten Sätze, welche aus
Wörtern
Inspect solutions of various
and
bestehen[2,
Seite
231].
Im
sel-
ben Kapitel werden noch weitere Beispiele
other disciplines of science, phenature,
war
Hierachie
Knowledge Ontology: Bücherein enthal-
für das Buch Cybernetics Oriented Pro-
of
Heller
gewisse
Beispiele dafür bringt er im Kapitel 7.3.1
Christian Heller beschreibt seine Motivation
nomenons
Christian
eine
genannt.
ap-
ply them to software engineer-
Der doppelthierarchische Ansatz ist in
ing
out
Kombination mit dem Schema der zen-
be
trale Verständnispunkt der kybernetikorien-
if
...
in
existing
order
to
nd
weaknesses
can
tierten Programmierung. Dabei werden zwei
eliminated. [2, Seite 161]
Hierarchien verwendet: Ein Wissensbaum,
welcher die Beziehungen der Objekte un-
Auch er versucht diesen Ansatz, welcher
tereinander hierarchisch abbildet, stellt die
wieder und wieder zu Durchbrüchen in der
erste Hierarchie dar. Teilweise wird dieser
Wissenschaft geführt hat: Durch das her-
Strang
anziehen von Naturphänomenen und Ergeb-
auch
einzelnen Objekten die Zweite.
sollen Schwächen in modernen Programmierparadigmen beseitigt werden.
Dieses
Kapitel
Herleitung
die
Beschäftung
mit
dem
Mikro-/Makro-Kosmos
bezeichnet. Die Metainformationen an den
nissen aus anderen Wissenschaftsdisziplinen
Durch
als
Körp-
der
beschäftigt
der
Herleitung
Hierarchie
des
im
sich
mit
(Kapitel
Buch
oft
der
2.1),
erwäh-
er, dem Geist, dem menschlichen Denken
nten Schemas (Kapitel 2.2), sowie des
und vielen anderen technischen und wis-
Zusammenschlusses
senschaftlichen, aber auch philosophischen
und
Punkten hat sich der Ansatz einer Dop-
2.3).
deren
zur
praktischen
Doppelhierarchie
Nutzen
(Kapitel
pelhierarchie herauskristallisiert.
Das nachfolgende Kapitel beschäftigt sich
mit
der
Model,
Herleitung
hin
zu
von
einem
einem
2.1 Herleitung des hierarchischen
Single
Modelles
Hierarchischem
Modell, sowie dem zu Grunde liegenden
Während der Erstellung von CYBOP ging
Schema um zu verdeutlichen, wieso von ein-
die
er Doppelhierarchie gesprochen wird. Am
Entwicklung
der
einem Single Model
Ende des Kapitels, wird für dieses Wis-
Datenstruktur
von
Ansatz über einen
semistrukturierten Ansatz hin zu einem -
sen eine mögliche praktische Anwendung
nalen Ansatz, in welchem die Struktur über
vorgestellt.
eine Hierarchie abgebildet wurde.
Das abschlieÿende Kapitel stellt den dop-
Das Single Model ist die heutzutage am
pelthierarchischen
der
weitesten verbreitete Struktur. Singel Mod-
Programmiersprache Python dar und ver-
el steht für einziges Model. Hierbei wird
sucht das zuvor gefundene Beispiel zu real-
für
isieren.
gelegt, welche anschlieÿend untereinander
Ansatz
mit
Hilfe
2
jeden
Typen
eine
eigene
Klasse
an-
2.2 Schema
verweisen. Auf Seite 218 zeigt Heller[2] hierfür ein Beispiel: Die Klasse Person hat
mehrere Attribute wie zum Beispiel das
Der erste Teil der Doppelhierarchie wurde
Geburtsdatum, Geschlecht, der Name oder
im voran gegangenen Kapitel erläutert. Nun
die Adresse. Der Name und die Adresse sind
fehlt lediglich noch der zweite Teil: Das
dabei komplexere Strukturen und haben
Schema. Abbildung 1 ist dem Buch Cy-
jeweils eine eigene Klasse. Im selben Kapi-
bernetics Oriented Programming entnom-
tel werden noch einige Probleme an diesem
men und zeigt den Aufbau des Schemas,
Ansatz aufgezeigt. So ist zum Beispiel eine
welchem ein jedes Objekt (Ausnahmen bie-
Erweiterung
ten hier primitive Datentypen) in CYBOP
bestehender
Strukturen
nur
schwer möglich.
zu Grunde liegen. Es braucht einen eindeutigen Bezeichner (name) sowie eine Ab-
Darauf aufbauend existiert das Semi Structured
Model,
strukturiertes
werden
laut
was
übersetzt
Modell
Heller[2,
straktion (abstraction). Letzteres ist mit
teilweise
bedeutet.
Seite219]
dem Typ eines Objektes in anderen Pro-
Hierbei
grammiersprachen vergleichbar. Alle weit-
Named
eren Informationen werden dynamisch in
Values verwendet. Diese werden in Listen
gespeichert
und
können
details gespeichert. Die in Kapitel 1 1
dynamisch
zu
hinzugefügt und verändert werden. Auÿer-
Relation in Bezug auf model wird
für die im Kapitel 2.1 vorgestellte Hierarchie
dem haben sie alle den einheitlichen Typ
benötigt. Diese Informationen stammen aus
Item.
Das
n
dem Kapitel 7.3.2 des Buches Cybernetics
hierarchische
Model
baut
nun
Oriented Programming. Für weitere Infor-
wiederum auf das Semi Structured Model
mationen empfehle ich dieses Kapitel, sowie
auf. Heller beschreibt dieses Model im Kapi-
die Kapitel 7.1.3 und 7.2.5.[2]
tel 7.2 Design Reections unter der Überschrift Hierarchical Model [2, Seite 220].
Nachdem nun kurz der Aufbau des Schemas
Es gibt lediglich eine verbleibende Klasse,
vorgestellt wurde, wird sich im nächsten
welche keine fest denierten Attribute hat.
Kapitel mit der aus dem Schema sowie der
Diese werden dynamisch hinzugefügt und
hierarchischen Struktur entstehenden Dop-
verwenden dabei dasselbe Model. So ent-
pelhierarchie beschäftigt. Auÿerdem wird
steht
auf
eine
Hierarchie,
welche
stark
dem
Struktur
ndet
im
egal
wie
klein
oder
praktischer Nutzen
groÿ,
sind Teil von gröÿeren. Im Umkehrschluss
In den Kapiteln 2.1 und 2.2 wurde das hi-
gilt, alle Dinge enthalten kleinere. Nehmen
erarchische Modell, sowie das in CYBOP
wir hierzu folgendes Beispiel: Es existiert
ein
beliebiges
Sonnensystem.
Dieses
verwendete Schema vorgestellt. Beide Mod-
ex-
elle ergeben zusammen den doppelthierar-
istiert wiederum in unserer Sonnenstraÿe
(Makro-Kosmos)
und
kann
eingegan-
2.3 Die Doppelhierarchie und deren
Hierarchie dar: den Mikro-/Makro-Kosmos.
Dinge,
Nutzen
cybernetischen
Ansatz ihe Verwendung. Sie stellt die erste
Alle
praktischen
gen.
menschlichen Denken angelehnt ist.
Diese
einen
Planeten
chischen Ansatz, welche den gedanklichen
en-
Kern beim kybernetischen Programmieren
thalten (Mikro-Kosmos). Dies könnte man
darstellen.
nun weiter fortführen. Neben dem Mirko/Makro-Kosmos gibt es noch eine zweite
Es gibt mehrere Objekte, welche in ein-
Hierarchie, weshalb von einer Doppelhier-
er
achie gesprochen wird. Die zweite Hierar-
den. Dabei sollte die hierarchische Verknüp-
chie ist das Schema und wird im nachfolgen-
fung der Objekte logisch erfolgen um eine
den Kapitel vorgestellt.
Nachvollziehbarkeit zu ermöglichen. Jedes
3
hierarchischen
Struktur
abgelegt
wer-
Abbildung 1: Knowledge Schema mit Metainformationen[2, Seite 234]
einzelnen
Objekte
formationen,
verfügt
welche
über
dynamisch
Metain-
groÿe Teile der Verständlichkeit und des hi-
hinzuge-
erarchischen Ansatzes verloren.
fügt und bearbeitet werden können. Diese
Metainformationen können ebenfalls in ein-
Das nachfolgende Kapitel versucht genau
er hierachischen Form vorliegen.
das zu überbrücken: Es wird der doppelt-
CYBOP
stellt
nicht
den
erste
hierarchische Ansatz von CYBOP versucht
Versuch
in
dar, in der Informatik daten hierchisch zur
Stelle
abzulegen.
So
objektorientierte
seien
an
Zur
dieser
Datenbanken
Objektorientierten
Programmier-
sprache Python zur Verfügung zu stellen.
Verfügung zu stellen, zu verwenden oder
persistent
der
persistenten
Datenhaltung
wird
die
zuvorgenannte ZODB[4] verwendet. Bei der
wie
ZODB handelt es sich um die Zope Object
die ZODB für Python[4] oder db40
Database, einer objektorientierten Daten-
für Java oder .NET[5] zu nennen, welche
bank, welche dem Zope-Projekt[6] entsprun-
meist die Möglichkeit einer hierachischen
gen ist.
Verwendung mitbringen. Der Vorteil solcher Datenbanken liegt in der fehlenden Abstraktionsschicht zwischen Datenbank und
3 Darstellung mittels Python
Anwendung. Bei relationalen Datenbanken
ist eine ORM (Object Relational Mapper)
Schicht
nötig
um
die
Daten
aus
der Datenbank in Objekte zu serialisieren
Der
und
Heller,
nach
dem
Ändern
rialisieren
und
zu
wieder
zu
dese-
kybernetischorientierte
welcher
im
Kapitel
Ansatz
2
nach
vorgestellt
Allerdings
wurde, setzt einen hohen Grad an dyna-
werden die hierarchisch vorliegenden Ob-
mischer Programmierung vorraus. Diesen
jekte anschlieÿend mit anderen Program-
hatte
mierparadigmen vermischt. Dadurch gehen
CYBOL[1]
speichern.
4
Heller
in
der
erschaen.
Programmiersprache
Aber
auch
andere
Programmiersprachen
können
diese
An-
zurückgegeben werden. Auf das
forderung erfüllen.
Python
ist
Beispiel angewendet, sieht dies wie folgt
eine
sehr
dynamische
aus:
Pro-
1
grammiersprache, in welcher es mit wenig
Aufwand
möglich
archischen
Testobject
ist
Ansatz
den
zu
doppelthier-
2
implementieren.
>>> myobject.__getattribute__('
name')
'Testobject'
Dieses Kapitel beschäftigt sich mit diesem
Vorhabden
und
erläutert,
welche
Dieses Wissen genügt, um die notwendi-
weit-
gen
eren Möglichkeiten in Python über Meta-
zu
Programmierung möglich wären.
Funktionen
in
implementieren
hinzufügen
und
eine
eigene
Klasse
um
das
dynamische
lesen
von
Attributen
an Objekten zu ermöglichen. Funktionen,
deren
3.1 Der doppelthierarchische Ansatz in
Namen
Python
trachten.
welche
fügt
in
jedes
viel
Funktionalität
mit
Python
Objekt
zu
in
nutzen.
Python
So
ver-
über
eine
__setattr__(prop, value)-Methode.
greifen
Attribute
hinzufügen.
In
gendem Beispiel wird eine Klasse
duch
hinzugefügt.
Punkt-Notation
Anschlieÿend
darauf
2
3
4
5
6
7
8
9
10
11
diese
können,
der
wird,
wird
eine
Funktio-
deutiger
Pfad
Liste
Properties
gemäÿ
zum
Objekt
zur
vewendet.
nach
deutiger Bezeichner) sowie der
fol-
den
name
path
im
An(ein(ein-
Wissens-
baum) gespeichert. Der Pfad ist notwendig
um anhand des Objektes herausnden zu
At-
können, in welchem Punkt des Wissens-
dy-
baumes er gespeichert liegt.
kann
zugegrien
1
# ~ encoding: utf-8 ~
2
>>> class Testobject(object):
...
pass
...
>>> myobject = Testobject()
>>> myobject.name
Traceback (most recent call last):
File "<stdin>", line 1, in <
module>
AttributeError: 'Testobject'
object has no attribute 'name'
>>> myobject.__setattr__('name', '
Testobject')
>>> myobject.name
'Testobject'
3
5
6
7
8
def __init__(self, name, path=
""):
self.name = name
self.path = path
self.properties = []
9
10
11
12
13
def add_property(self, prop,
value):
"""
"""
self.__setattr__(prop,
value)
14
Zum Auslesen einmal gesetzter Attribute 16
gibt es ebenfalls eine Funktion in Python: 17
Damit
class Part(object):
4
15
__getattribute__(prop).
werden
forderungen an das Schema, der
werden:
1
zu
Auÿerdem
Ihr
Test-
object erstellt, welche nicht über das
tribut name verfügt. Dieses wird erst
Daher
Datenhaltung
einen Wert übergeben und auf diesem Wege
namisch
begin-
erzeit auf alle verfügbaren Attribute zu-
kann man einen Variablenbezeichner, sowie
dynamisch
__
mit
in get_property() beziehungsweise
add_property() gekapselt. Um auch jed-
sich bringt um den doppelthierarchischen
Ansatz
Python
nen
Python ist eine dynamische Programmiersprache,
in
nen, sind als private Funktionen zu be-
kann 18
über den Namen des Attributes desen Wert
5
def get_property(self, prop):
"""
"""
return self.
__getattribute__(prop)
Um den Mikro-/Makro-Kosmos
(beziehungsweise
Hierarchie)
die
abbilden
zu
Diese 23 Zeilen reichen aus um den dop-
Teil-/Ganzeskönnen,
pelthierarchischen
müssen
Ansatz
in
nutzen. Durch das Erben von
Python
zu
Persistent
auch die Parts, welche in dem aktuellen
ist es auch möglich, sie in der ZODB
Part existieren, gespeichert werden. Hierzu
abzuspeichern. Die Dateien part.py und
bietet sich ein Dictionary, also eine Liste
start.py sind im Anhang zu nden. Bei der
von Schlüssel-Wert-Paaren an. Auÿerdem
start.py handelt es sich um einen Webser-
sollen die Daten persistent in der objekto-
vice, welcher es erlaubt
rientieren Datenbank ZODB gespeichert
namisch anzulegen und abzurufen.
werden. Gegenwärtig erbt die Klasse
von
der
object.
allgemeinen
Part-Objekte
dy-
Part
Python-Superklasse
3.2 Weitergehende
Um die Persistenz zu gewährleis-
Meta-Programmierung in Python
ten, sowie um die Klasse wie ein Dictionary verwenden zu können, wird statt von
object von den Klassen Persistent und
UserDict geerbt. Um auf die Parts speich-
Mit
der
Klasse,
zuvor
sowie
weiteren,
ern zu können, muss das Klassen-Attribut
tel
data
Programmierung
als
Dictionary
vorliegen.
Sind
all
vorgestellten
erläuterten
in
diesem
Möglichkeiten
ist
diese Anforderungen implementiert, sieht
äuÿerst
dynamische
die Klasse wie folgt aus:
stellen.
Python
es
Kapi-
der
Meta-
möglich,
Anwendung
bietet
Part-
neben
zu
dem
eine
erdy-
namischen Hinzufügen von Attributen noch
1
2
3
# ~ encoding: utf-8 ~
import persistent
from UserDict import UserDict
die Möglichkeit zur Laufzeit Funktionen,
Klassen
Bei
4
9
10
11
12
15
16
17
18
21
22
23
spricht
man
an-
im Folgenden kurz vorgestellt und sind allesamt (Wissen sowie abgeänderte Beispiele)
def __init__(self, name, path=
""):
self.name = name
self.path = path
self.properties = []
self.data = {}
den
Vortrag
Python
Metaprogramming
for Mad Scientists and Evil Geniuses von
Walker Hale entnommen[7].
Synthetische Funktionen
def add_property(self, prop,
value):
"""
"""
self.__setattr__(prop,
value)
self.properties.append(prop
)
In
vielen
Scriptsprachen
beziehungsweise
dynamischen Programmiersprachen ist es
möglich,
Programmcode
aus
Strings
di-
rekt einzulesen. In JavaScript ist dies zum
Beispiel über die Funktion
Python wird dafür
eval möglich. In
exec verwendet. Im Fol-
genden ein Beispiel:
19
20
Objekten
implementieren.
Modulen. Diese drei Möglichkeiten werden
13
14
zu
Klassen/
class Part(persistent.Persistent,
UserDict):
7
8
solchen
Module
schlieÿend von synthetischen Funktionen/
5
6
und
1
def get_property(self, prop):
"""
"""
return self.
__getattribute__(prop)
2
3
4
5
6
7
6
>>> d = {}
>>> exec """\
... def say_hello_to(name):
...
print("Hello %s" % (name))
... """ in d
>>> d.keys()
['__builtins__', 'say_hello_to']
8
9
10
>>> say_hello_to = d['say_hello_to
']
>>> say_hello_to("Bob")
Hello Bob
Synthetische Module
Mit Hilfe des
new
Modules ist es möglich,
zur Laufzeit neue Python-Module zu erzeugen. Anschlieÿend kann man sie mit Hil-
Hierbei wurde die Funktion
erstellt
und
anschlieÿend
fe des
say_hello_to
demonstriert.
Funktionen aus einem String erzeugt wer-
1
den, können sie ein enormes Sicherheits-
2
risiko darstellen!
3
4
5
Synthetische Klassen
6
7
In dem Vortrag von Walker Hale wird klar,
dass eine Klasse in Python nichts anderes
8
ist als ein Dictionary, welches auf Funktionen zeigt. In Python gibt es die Funktion
welche den Typen eines Objektes
zurück gibt. Diese kann allerdings auch dazu
genutzt werden, generisch neue Klassen zu
erstellen:
1
2
3
4
5
6
7
8
9
10
11
9
10
11
12
>>> def __init__(self, name):
...
self.name = name
...
>>> def say_hello_to(self, name):
...
print("%s says hello to %s"
% (self.name, name))
...
>>> d = dict(__init__=__init__,
say_hello_to=say_hello_to)
>>> SynteticClass = type('
SynteticClass', (), d)
>>> obj = SynteticClass('Tim')
>>> obj.say_hello_to('Bob')
Tim says hello to Bob
Modules registrieren und an-
wie folgt von statten:
Allerdings sollte man hierbei aufpassen: Da
type(),
sys
schlieÿend normal importieren. Dies geht
13
14
15
>>> import new, sys
>>> my_module = new.module('
say_hello_module', 'A fake
module.')
>>> def say_hello_to(name):
...
print("Hello %s" % (name))
...
>>> my_module.say_hello_to =
say_hello_to
>>> sys.modules['say_hello_module'
] = my_module
>>> del new, sys, say_hello_to,
my_module
>>> my_module.say_hello_to("Bob")
Traceback (most recent call last):
File "<stdin>", line 1, in <
module>
NameError: name 'my_module' is not
defined
>>> import say_hello_module
>>> say_hello_module.say_hello_to(
"Bob")
Hello Bob
Auch hier sollte man aufpassen: auf diese
Weise ist es möglich, bestehende Module
zu überschreiben. Bei sogenannten MonkyPatches (Bezeichnung für das Patchen von
Code zur Laufzeit) ist dieser Eekt sogar
erwünscht: Man bekommt die Möglichkeit
bestehende
Module
zu
bearbeiten,
ohne
ihren Code ändern zu müssen.
Im eben gezeigten Beispiel wurden zwei
3.3 Warum Metaprogrammierung?
Funktionen erzeugt und in einem Dictionary gespeichert. Anschlieÿend wurde daraus eine Klasse erstellt, instanziiert und die
Funktion
say_hello_to
Nachdem nun ausführlich die Möglichkeit-
ausgeführt.
en
der
Metaprogrammierung
dargelegt
wurden,
stellt
sich
in
die
Python
Frage:
Auf diese Weise ist es möglich, die Part
Warum oder wofür Metaprogrammierung?
Klasse dynamisch zu erweitern.
Wie bereits zuvor genannt worden ist, stellt
7
Abbildung 2: Schematischer Programmablauf ohne Metaprogrammierung
die hierarchische Struktur der Datenhaltung
darestellen. Dazu beschäftigte Dokument
das besondere an CYBOP dar.
im Kapitel 2 mit den theoretischen Grundlagen
Wenn nun Programmcode auf die Daten-
aggieren
in
diesem
verschaft. Im zweiten Schritt erläutert es
Fall
das verwendete Schema genauer und fügt
nur als Wrapper. Also als Programmcode,
welcher
die
Instanzen
der
Part
Dies
die Herleitung des hierachischen Modelles
hend losgelöÿt von der hierarchischen StrukFunktionen
Programmieransatzes.
geschiet, indem es zu erst einen Blick auf
struktur zugreift, geschiet dies weitestgetur.
dieses
beides abschlieÿend als Doppelhierarchie
Klasse
zusammen.
umschlieÿt und so Funktionalität auf ihr
ausführt. Die Funktionalität liegt allerd-
Das
ings nicht selbst bei den Instanzen. Ab-
er möglichen Umsetzung des doppelthier-
bildung 2 zeigt dies schematisch. Mit Hil-
achischen
fe der Metaprogrammierung ist es unter
sprache Python. Dazu wird im Kapitel 3.1
anderem
kurz das dynamische Hinzufügen von At-
möglich,
dynamisch
Funktionen
Kapitel
3
beschäftigt
Ansatzes
in
der
sich
mit
ein-
Programmier-
fügen.
tributen erklärt und wie daraus eine gener-
Diese Funktionen stehen anschlieÿend nicht
ische Klasse entsteht. Anschlieÿend wird
der
an
Instanzen
von
Objekten
zu
lediglich
in Kapitel 3.2 weitergehende Möglichkeiten
einzelnen Instanzen zur Verfügung. Durch
der Metaprogrammierung in Python erklärt
Metaprogrammierung kann das Ziel erreicht
um schlussendlich in Kapitel3.3 kurz zu er-
werden, nicht nur die Datenhaltung, son-
läutern, das dank der Metaprogrammierung
dern auch den Programmablauf hierarchisch
die Funktionalitäten direkt in den Wissens-
darzustellen. Dies wird durch Abbildung 3
baum hinzugefügt werden können, statt sie
dargestellt.
nebenher
gesammten
Klasse
sondern
zu
verwenden.
Dies
ermöglicht
einen weitaus dynamischeren Ansatz, welcher näher an der Programmiersprache CY-
4 Zusammenfassung
BOL ist.
Dieses Dokument hilft nicht nur Entwick-
Diese Arbeit soll eine Handreichung zum
lern, welche sich neu mit dem Programmier-
besseren Verständnis des cybernetischori-
ansatz CYBOP auseinander setzen dessen
entierten Ansatzes nach Christian Heller
theoretischen Ansatz zu verstehen, sondern
8
Abbildung 3: Schematischer Programmablauf mit Metaprogrammierung
http://de.wikipedia.
org/wiki/Lotuseffekt.
zeigt auch, das dieser nicht nur an die
-
Sprache CYBOL gebunden ist.
Lotuseekt,
[4] Zope Foundation.
Data Base,
Literatur
[5] VERSANT CORP. db40,
db4o.com/.
[1] Dr. Christian Heller. Svn Repository des
http://savannah.
nongnu.org/svn/?group=cybop.
[6] Zope Foundation.
CYBOP Projektes,
[2] Dr. Christian Heller.
Zodb - Zope Object
http://www.zodb.org/.
http://www.
[7] Walker Hale. Python Metaprogramming
Cybernetics Ori-
for
ented Programming. Tux Tax, 2006.
Mad
Scientists
and
Evil
Genius-
http://www.youtube.com/watch?
v=Adr_QuDZxuM.
es,
[3] Wikipedia Foundation Inc.
Zope,
zope.org/.
http://www.
Wikipedia
9
Anhang
part.py
1
2
3
# ~ encoding: utf-8 ~
import persistent
from UserDict import UserDict
4
5
6
class Part(persistent.Persistent, UserDict):
7
8
9
10
11
12
def __init__(self, name, path=""):
self.name = name
self.path = path
self.properties = []
self.data = {}
13
14
15
16
17
18
def add_property(self, prop, value):
"""
"""
self.__setattr__(prop, value)
self.properties.append(prop)
19
20
21
22
23
def get_property(self, prop):
"""
"""
return self.__getattribute__(prop)
10
start.py
1
2
# ~ encoding: utf-8 ~
3
4
5
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import cgi
6
7
8
9
from ZODB.FileStorage import FileStorage
from ZODB.DB import DB
import transaction
10
11
from part import Part
12
13
server = None
14
15
16
class CybopHTTPServer(HTTPServer):
17
18
19
20
21
22
23
def __init__(self, (HOST, PORT), Handler):
self.storage = FileStorage('Data.fs')
self.db = DB(self.storage)
self.connection = self.db.open()
self.root = self.connection.root()
HTTPServer.__init__(self, (HOST, PORT), Handler)
24
25
26
class CybopHTTPHandler(BaseHTTPRequestHandler):
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def do_GET(self):
"""
"""
path_stack, params = self._get_path_stack()
if len(params) == 1 and 'name' in params:
self.send_response(301)
redirect_path = '/'.join(path_stack) + '/' + params['name'].
lower()
self.send_header("Location", redirect_path)
self.end_headers()
pass
elif path_stack[0] == '':
self.return_root()
elif path_stack[0] == 'favicon.ico':
return
else:
context, remaining_stack = self._travers_object(path_stack)
if not remaining_stack:
self.return_information_view(context)
elif len(remaining_stack) == 1:
self.return_add_view(context)
else:
self.redirect_method(context)
50
51
def do_POST(self):
11
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
"""
"""
path_stack, params = self._get_path_stack()
context, remaining_stack = self._travers_object(path_stack)
params = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD': 'POST',
'CONTENT_TYPE': self.headers['Content-Type'],
}
)
new_part = Part(remaining_stack[0].title(), path=self.path)
for param in params:
if param[:5] == 'value':
pass
else:
number = param[-1:]
if 'value' + number in params:
new_part.add_property(params[param].value, params['value'
+ number].value)
context[remaining_stack[0]] = new_part
self.send_response(201)
self.send_header("Location", '/')
self.end_headers()
transaction.commit()
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def return_information_view(self, context):
"""
"""
heading = '<h1>%s</h1>\n<h2>%s</h2>' % (context.name, context.path)
child_links = ["<li><a href='%s'>%s</a></li>" % (
context[key].path,
context[key].name
) for key in context.keys()]
body_text = ["<b>%s:</b><p>%s</p>" % (prop, context.get_property(
prop)) for prop in context.properties]
message = """%s\n
%s\n
<h3>All properties:</h3>
%s\n
90
91
92
93
94
95
96
97
<h3>All Subpages:</h3>\n
<ul>\n%s</ul>
""" % (heading, self._add_new_form(), '\n'.join(body_text), '\n'.
join(child_links))
self.send_response(200)
self.end_headers()
self.wfile.write(message)
return
98
99
100
def return_add_view(self, context):
"""
12
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
self.send_response(200)
self.end_headers()
heading = "<h1>Add a new Part at the path %s</h1>" % (self.path)
add_form = """
<p>
You can now add your information to the Part.
</p>
<form method="POST">
<table>
<tr>
<td><b>attribute name<b></td>
<td><b>attribute value</b></td>
</tr>
<tr>
<td>
<input name="attribute1" type="text" size="30"/>
</td>
<td>
<textarea name="value1" type="textarea" cols="30" rows="4"></
textarea>
</td>
</tr>
<tr>
<td>
<input name="attribute2" type="text" size="30" />
</td>
<td>
<textarea name="value2" type="textarea" cols="30" rows="4"></
textarea>
</td>
</tr>
<tr>
<td>
<input name="attribute3" type="text" size="30" />
</td>
<td>
<textarea name="value3" type="textarea" cols="30" rows="4"></
textarea>
</td>
</tr>
<tr>
<td>
<input name="attribute4" type="text" size="30" />
</td>
<td>
<textarea name="value4" type="textarea" cols="30" rows="4"></
textarea>
</td>
</tr>
<tr>
<td>
13
149
150
151
152
153
154
155
156
157
158
159
160
<input name="attribute5" type="text" size="30" />
</td>
<td>
<textarea name="value5" type="textarea" cols="30" rows="4"></
textarea>
</td>
</tr>
</table>
<input type="submit" value=" Add ">
</form>
"""
self.wfile.write("%s\n%s" % (heading, add_form))
return
161
162
163
164
165
166
167
168
169
170
171
def redirect_method(self, context):
"""
"""
self.send_response(301)
if context == self.server.root:
self.send_header("Location", '/')
else:
self.send_header("Location", context.path)
self.end_headers()
pass
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def _travers_object(self, path_stack, active_object=None):
active_element = None
if not active_object:
active_object = self.server.root
while path_stack != []:
active_element = path_stack.pop(0)
if active_element in active_object:
active_object = active_object[active_element]
active_element = None
else:
break
if active_element:
remaining_stack = [active_element] + path_stack
else:
remaining_stack = path_stack
return active_object, remaining_stack
189
190
191
192
193
194
195
196
197
198
def return_root(self):
heading = '<h1>Welcome to the Cybernetic Oriented Webservice</h1>'
child_links = ["<li><a href='%s'>%s</a></li>" % (
self.server.root[key].path,
self.server.root[key].name
) for key in self.server.root.keys()]
message = "%s\n%s<h3>All Subpages:</h3>\n<ul>\n%s</ul>" % (heading,
self._add_new_form(), '\n'.join(child_links))
self.send_response(200)
self.end_headers()
14
199
200
self.wfile.write(message)
return
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
def _get_path_stack(self):
path_stack = self.path.split('/')
path_stack.pop(0)
if path_stack == [''] or '?' not in path_stack[-1]:
return path_stack, {}
else:
params = {}
stack_rest, param_string = path_stack.pop(-1).split('?')
if stack_rest != ['']:
path_stack.append(stack_rest)
param_list = param_string.split(',')
for param_pair in param_list:
attribute, argument = param_pair.split('=')
params[attribute] = argument
return path_stack, params
217
218
219
220
221
222
def _add_new_form(self):
return """<form>
Add new Subpage with name: <input name="name" type="text" size="30"
/> <input type="submit" value=" Ok ">
</form>
"""
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
if __name__ == '__main__':
try:
HOST, PORT = "localhost", 9999
server = CybopHTTPServer((HOST, PORT), CybopHTTPHandler)
print("\n**********************************************************\
n" + \
"***
***\n" +\
"*** This Server handels WebRequests and works with a ***\n" +\
"*** Cybernetics Oriented Database Model in the ***\n" +\
"*** Backend.
***\n" +\
"***
***\n" +\
"*** Starting TCPServer on %s:%s
***\n" % (HOST, PORT)
+ \
"*** To shut down, press <CTRL-C>
***\n" +\
"***
***\n" +\
"**********************************************************\n"
)
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
server.connection.close()
server.db.pack()
server.db.close()
server.storage.close()
15
Herunterladen