Python Code Frage

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
wernerf
User
Beiträge: 4
Registriert: Samstag 13. Juni 2015, 18:26
Wohnort: Nürnberg

Hallo zusammen,
Sorry, für den etwas länglichen Text, aber ich weiss nicht wie ich es anders
Beschreiben soll.

Meine Kenntnisse in Python sind sehr rudimentär und was objektorientierte
Programmierung angeht, habe ich wenig Wissen. Bisher programmierte ich
in Perl oder Bash.

Meine Python Klassen soll eine Verbindung zu einem Programm auf einem oder
mehreren Rechnern mittels eines Socket herstellen, dorthin Befehle senden
und das Ergebnis holen. Die Befehle sind als Methoden in einer Klasse
definiert.
Soweit funktioniert alles auch, aber jetzt sollen Methoden mit eventuell
gleichem Namen aber anderen Argumenten und anderen Inhalt für ein anderes
Zielprogramm hinzukommen.

Wenn also eine Verbindung zu einem Rechner mit Zielprogramm A aufgebaut werden soll,
sollen die Methoden in der Datei "a_methoden.py" benutzt werden, bei Zielprogramm B
die Methoden in der Datei "b_methoden.py".

Aus Sicht des Anwenders soll das aber nicht sichtbar sein. Er soll etwas
Initialisieren und dann die Methode benutzen können. Zu welchem Zielprogramm (A/B)
eine Verbindung aufgebaut werden soll, kann aus Angaben, die bei der Initialisierung
gemacht werden, ermittelt werden.

Wie mache ich so etwas ?

Beispiel:

Anwendersicht:
# So soll ein Anwender vereinfacht den Code benutzen.

Code: Alles auswählen

from testanwendung  import *

  aObj = Testanwendung("A", a, b)    # Initialisierung für Prg A
  resultA = aObj.Befehl1(para1, para2) 

  bObj = Testanwendung("B", c, d)    # Initialisierung für Prg B
  resultB = bObj.Befehl1(para1)
aktuelle Implementierung nur für Prg "A":

testanwendung.py In dieser Datei befindet sich der nächste Code.

Code: Alles auswählen

class TestanwendungClinet:
    # Klasse, für zentrale Funktionen
    
    def __init__(self, p1, p2):
      # Initialisiere alle später benutzten Variablen
    
    def connect(self, ipAddr):
      # Verbinde zu benötigtem Rechner und merke die Verbindungsdaten
    
    def send(self, command, args):
      # Sende den Befehl mit argumenten
    
    def receive(self, ...):
      # Lese was von der Verbindung kommt und gebe es an den Anwender zurück
    
    
  class Testanwendung:
    # In dieser Class sind alle Befehle für Prg A definiert und ein paar
    # 'common' Methoden, die auch später für beide Prg gelten werden
    
    def __init__(self, name, p1, p2):
      # 'name' wird noch nicht ausgewertet
      self.std = TestanwendungClinet(p1, p2)

    def Befehl1(self, para1)
      # Baue aus para1 ein Kommando und sende es
      command = "befehl1"
      result = self.std.send(command, args)
    
    def Befehl2(...)
EOF testanwendung.py

------------------------------
erweiterten Funktonalität:

Da die aktuelle Implementierung schon von vielen Leuten benutzt wird,
sollen die notwendigen Änderungen möglichst keine Änderung für die Leute bedeuten.
Deren Programme sollen gleich bleiben. Alle notwendigen Daten aus denen
A oder B ermitteln werden kann, werden jetzt schon bei der Initialisierung
übergeben.

testanwendung.py Hier sollen alle gemeinsamm genutzten Methoden verbleiben
a_methods.py Hier sollen nur die für A gültigen Methoden enthalten sein
Sie müssen also von testanwendung.py dorthin verschoben werden.
b_methods.py Hier sollen nur die für B gültigen Methoden enthalten sein

Die Aufteilung auf 2 Files ist notwendig, weil "b_methoden.py" von einer
anderen Person in einem anderen Land gepflegt wird und ich will keine
Änderungsprobleme.

Ist folgendes möglich ?
Wie genau ?

Code: Alles auswählen

class Testanwendung:
  def __init__(self, name, p1, p2):
    # Jetzt 'name' wird ausgewertet
    if name == "A":
      # Lade oder initialisiere Methoden für A
      # was muss ich hier machen, dass später über aObj die Methoden für A benutzen kann ?
    if name == "B":
      # Lade oder initialisiere Methoden für B
      # was muss ich hier machen, dass später über bObj die Methoden für B benutzen kann ?

    self.std = TestanwendungClinet(p1, p2) # Initialisieren muss ich auch noch
                                           # Hier oder im IF Block ?
--------------------------------
Wie in dem Anwendercode ganz oben zu sehen ist, muss es möglich sein Methoden für A und B gleichzeitig zu verwenden.

Geht das über:
- für A: TestanwendungA(Testanwendung):
- für B: TestanwendungB(Testanwendung):

Oder geht das überhaupt nicht wie ich mir das Vorstelle.

herzlichen Danke für's Lesen und für einen Tipp
Werner
Zuletzt geändert von cofi am Samstag 13. Juni 2015, 19:17, insgesamt 1-mal geändert.
Grund: Code Markup korrigiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Willkommen im Forum und zu Python!
Fuer die Zukunft setze Python-Code bitte in [ python ] [/ python ] Tags, weil sonst die Einrueckung verloren geht.

Das Facade Pattern, dass du am Ende umreisst sollte doch das Problem loesen? Welche Probleme siehst du da?
Konkret wuerde man evtl noch die jeweiligen Testanwendungen in `Testanwendung` erstellen und dort dann zur "Unteranwendung" dispatchen. Indem man `__getattr__` implementiert koennte man sich da noch Code sparen, ungetestet:

Code: Alles auswählen

class Testanwendung(object):
    def __init__(self, name, *args)
        self._program = TESTPROGRAMS[name](*args)
    
     def __getattr__(self, attr):
         return getattr(self._program, attr)
BlackJack

@wernerf: Ich würde das ganz einfach nicht mit einer Klasse lösen wollen. Wenn man Anhand der Argumente unterscheiden kann welche Klasse tatsächlich verwendet werden soll, könnte man auch einfach an der Stelle wo man die Argumente übergibt die passende Klasse verwenden. Oder man schreibt eine Funktion die einem je nach Argumenten das passende Exemplar zurück gibt. Alles andere läuft irgendwie auf ”Magie” hinaus.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@wernerf: das hört sich nach einem typischen Anwendungsfall für eine Factory-Function an. Du lieferst einfach die passende Klasse zurück:

Code: Alles auswählen

import methods_a
import methods_b

NAME2CLS = {
    'A': methods_a.class_a,
    'B': methods_b.class_b,
}

def create_app(name, p1, p2):
    cls = NAME2CLS[name|
    return cls(p1, p2)
wernerf
User
Beiträge: 4
Registriert: Samstag 13. Juni 2015, 18:26
Wohnort: Nürnberg

@BlackJack:
Danke für Deinen Vorschlag.
Aber dieser würde darauf hinauslaufen, dass sich die Maintainer der Files bei jeder Änderungen absprechen und das ist was wir auf keinen Fall wollen. Die befinden sich nicht nur in einem anderen Land, sondern es kommen noch ca. 6 Std. Zeitunterschied hinzu.
Ausserdem habe ich nicht die Zeit solche Abstimmungen zu machen.
Die Lösung muss so aussehen, dass in "methods_b.py" bis auf Basisdinge freizügig codiert werden kann.
Das zugehörige Zielprogramm B wird nämlich auch an dem Standort entwickelt.

Das Python Programm von mir kann man mehr als eine Art Wrapper verstehen.

@cofi und @Sirius3:
Habe ich noch nie von gehört, aber das Wundert nicht wirklich.
Ich habe mir zum Testen eine Minimal Implementierung geschrieben. An der muss ich das ausprobieren.
Ich hoffe im Netz finde ich mehr dazu.

Werde mich sehr wahrscheinlich nochmal melden :roll:
Danke und Gruss
Werner

Danke und Gruss
Werner
BlackJack

@wernerf: Verstehe nicht wo man sich da absprechen müsste‽ Ob man nun beim Aufruf "a" oder "b" übergibt oder an der Stelle die passende Klasse auf Modul `a` oder `b` aufruft ist doch letztendlich ”das gleiche” nur eben etwas anders — einfacher/ohne ”Magie” — kodiert.

Und was das freizügig ändern angeht: Es gibt Versionsverwaltungssoftware und viele Programmierteams die über mehrere Zeitzonen verteilt sind und mit so etwas prima klar kommen. Allerdings nie ohne sich wenigstens über die Grundlegenden Schnittstellen abzusprechen.
wernerf
User
Beiträge: 4
Registriert: Samstag 13. Juni 2015, 18:26
Wohnort: Nürnberg

@BlackJack

Sorry, dann habe ich Dich wohl falsch verstanden.
Aber anhand der Argumente kann man das nicht unterscheiden, zumindest wahrscheinlich nicht nur.
"methods_B.py" gibt es noch nicht, so dass ich es aktuell nicht weiss.
Was aber sicher ist, bei der Initialisierung wird eine Datenstruktur übergeben, die die Info über A oder B oder was da in Zukunft sonst noch kommen mag enthält.

Gruss Werner
BlackJack

@wernerf: Natürlich kann man das alleine anhand der Argumente entscheiden. Das sagst Du doch auch selbst: Die Information ob a, b, oder … ist in einer übergebenen Datenstruktur enthalten.
wernerf
User
Beiträge: 4
Registriert: Samstag 13. Juni 2015, 18:26
Wohnort: Nürnberg

@BlackJack

ach so, das meinst du mit Argumente.
Ich dachte du meintest die Argumente bei
resultA = aObj.Befehl1(para1, para2)
von meinem Beispiel.
Aber ich habe mich heute mit einem Kollegen unterhalten, der mehr Ahnung von Python hat als ich
und habe ihm meinen bisherigen Code gezeigt und wir haben die neue Anforderung besprochen.
Dabei sind wir auf den Umstand gestossen, dass es nicht nur von "A" oder "B" abhängt, sondern auch von einer
Zahl, die in "para1" bei "resultA = aObj.Befehl1(para1, para2)" enthalten ist.
Seine Meinung kurz vor Feierabend war, dass sich das mit den geforderten Freiheitsgraden nicht mit
sinnvollem Aufwand realisieren lässt. Genaueres werden die nächsten Tage zeigen.
Mal sehen, was die Kollegen am anderen Standort dazu sagen :wink:

Darum, denke ich, macht es erst einmal keinen Sinn mein Problem hier weiter zu verfolgen.
Die genauen Anforderungen lassen sich nämlich nicht so einfach erklären.

vielen Dank an alle, die gelesen und mitgedacht haben.

Grüsse
Werner
Antworten