andie39‘s Fragen Thread

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.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Neue Frage: Komposition

Aktuell bin ich beim Thema Objektorierntierung

Klassen, Methoden

Und hier bei der Komposition.
Ich brauche das nicht erklären, wisst ihr besser.

Hier habe ich nun eine kleine Frage. Ich habe zwei Code Beispiele für Komposition.
Code 1 aus dem Internet
Code 2 aus einem Buch, das ich neben meinem Udemy Kurs lese.

Code 1

Code: Alles auswählen


class Employee: 
  
    
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
  
    
    def emp_data(self): 
        print('Name of Employee : ', self.name) 
        print('Age of Employee : ', self.age) 
  
  
class Data: 
    def __init__(self, address, salary, emp_obj): 
        self.address = address 
        self.salary = salary 
  
        
        self.emp_obj = emp_obj 
  
    
    def display(self): 
  
        
        
        self.emp_obj.emp_data() 
        print('Address of Employee : ', self.address) 
        print('Salary of Employee : ', self.salary) 
  

emp = Employee('Ronil', 20) 
  
data = Data('Indore', 25000, emp) 
  
data.display()

Hier ist es klar:
self.emp_obj.emp_data() emp_obj von data ist emp_obj und das ist emp
Also ist der code = emp.emp_data()
emp_data ist eine Klasse davor und definitert und wird durch emp = Employee('Ronil', 20)
Im Konstruktor gebildet.

Soweit alles klar hier auch wie Data konstruiert wird.

Nun Code 2:

Code: Alles auswählen


class WindowsMyDocuments:
    def save(self,document):
        destination = Path.home() / "Documents" / "scan.txt"
        print("Saving to: ", destination)
        destination.write_text(document)
        
        
class LinuxHomeDir:
    def save(self,document):
        destination = Path.home() / "scan.txt"
        print("Saving to: ", destination)
        destination.write_text(document)
        

class Fileprinter:
    def __init__(self, windows, linux):
        self._windows = windows
        self._linux = linux
    
    def print(self, document):
        destination =(
            self._linux
            if platform.system() = "linux"
            else self._windows
        )
        destination.save(document)
        
        
print_to_file = Fileprinter(
    windows = WindowsMyDocumemts(), 
    linux = LinuxHomeDir()
)

print_to_file.print(file1)

Auch hier eigentlich klar was mich hier irritiert ist:

print_to_file = Fileprinter(
windows = WindowsMyDocumemts(),
linux = LinuxHomeDir()
)

Das windows=WindowsMy…… ist doch nicht nötig oder?
Es geht doch auch wie in Code1:

print_to_file = Fileprinter(
WindowsMyDocumemts(),
LinuxHomeDir()
)



Oder irre ich mich?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Man kann Argumente per Position oder per Keyword übergeben. Da der Name eines Arguments meist schon viel über desse Funktion aussagt, ist es manchmal gar nicht verkehrt, die auch zu benennen, obwohl es eigentlich nicht nötig ist.
Grundsätzlich hat man dann natürlich auch die Eigenschaft, dass die Reihenfolge der Argumente ergal ist und gezielt nur bestimmte Argumente gesetzt werden können, während andere den Standardwert behalten.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

sparrow hat geschrieben: Sonntag 23. Januar 2022, 00:21 Man kann Argumente per Position oder per Keyword übergeben. Da der Name eines Arguments meist schon viel über desse Funktion aussagt, ist es manchmal gar nicht verkehrt, die auch zu benennen, obwohl es eigentlich nicht nötig ist.
Grundsätzlich hat man dann natürlich auch die Eigenschaft, dass die Reihenfolge der Argumente ergal ist und gezielt nur bestimmte Argumente gesetzt werden können, während andere den Standardwert behalten.
Heißt das ich mich nicht irre und das windows =windowsMy… unnötig ist?
Und man nur windowsMy… hätte schreiben können?
Benutzeravatar
__blackjack__
User
Beiträge: 13111
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@andie39: Also das erste Beispiel finde ich nicht klar und ich würde auch sagen das ist falsch. Erst einmal modelliert die Klasse `Employee` keinen Angestellten, denn dazu fehlen Eigenschaften die einen Angestellten ausmachen. Beispielsweise das Gehalt. Das was in `Employee` zusammengefasst wird, kann man vielleicht als `Person` bezeichnen.

Dann haben wir da Abkürzung (`emp_*`) in einem Namen und bei `Employee` ist dass dann auch noch die Abkürzung für die Klasse — was keinen Sinn macht, denn diese Information steht ja bereits im Klassennamen, die braucht man nicht noch mal wiederholen. Und bei Vererbung wird es dann komisch, weil die Methoden Abkürzungen enthalten die dann vielleicht gar nicht mehr zum Namen der abgeleiteten Klasse gehören.

Bleibt `data()`, was so gar kein guter Name für eine Methode ist, mal abgesehen davon, dass der Name supergenerisch ist. Und die Methode erfüllt die gleiche Aufgabe wie `Data.display()`, was sinnvoller benannt ist, und dann sollte das bei `Employee` bzw. `Person` vielleicht auch so heissen.

Bei `Data` ist der Name auch zu generisch. Wenn die erste Klasse `Person` heisst, würde man `Data` aber *nicht* `Employee` nennen wollen, denn ein `Employee` *ist* ja eine Person, das wäre also eine Vererbung und keine Komposition. Also bräuchte man einen Namen wo die *Bestandteile* Adresse, Gehalt, und Person tatsächlich sinnvoll sind. Vielleicht ein Arbeitsvertrag, also `EmploymentContract`.

In der zweiten Klasse ist dann `emp` wieder eine blöde Abkürzung. Insbesondere weil in Kontexten wo der Arbeitnehmer vorkommen kann, ja auch der Arbeitgeber eventuell irgend wo mal modelliert werden könnte. Und dann hat man lauter Code wo `emp`-Abkürzungen sind und darf dann jedes mal überlegen oder nachforschen ob da nun jeweils `employee` oder `employer` gemeint ist. Abk. s. i.d.R. doof. 🤡

Der Suffix `*_obj` macht in 99,99% der Fälle keinen Sinn, weil in Python *alles* was man an einen Namen binden kann, ein Objekt ist. Objekt und Wert sind in Python synonym.

Und ja ich weiss, dass das aus dem Internet ist und nicht von Dir, Du kannst da nichts für!

Code: Alles auswählen

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def display(self):
        print("Name of Person:", self.name)
        print("Age of Person:", self.age)


class EmploymentContract:
    def __init__(self, employee, address, salary):
        self.employee = employee
        self.address = address
        self.salary = salary

    def display(self):
        self.employee.display()
        print("Address of Employee:", self.address)
        print("Salary of Employee:", self.salary)


person = Person("Ronil", 20)
contract = EmploymentContract("Indore", 25_000, person)
contract.display()
Was man da inhaltlich noch anmerken könnte, wäre das `age` ungünstig ist. Da müsste man dann einmal im Jahr alle Daten durchgehen und das Alter um eins rauf setzen. Geburtsdatum macht da mehr Sinn. `age` kann man dann als `property()` anbieten, weil man das ja ausrechnen kann.

Beim zweiten Beispiel kann man die Namen der Argumente beim Aufruf auch weg lassen. Was mich bei dem Beispiel irritiert ist die leicht sinnlose Komplexität, denn die Plattform ändert sich nicht während der Laufzeit, und diese Entscheidung dann jedes mal beim Aufruf von `print()` zu treffen, macht überhaupt keinen Sinn.

Alle drei Klassen sind keine wirklichen Klassen. Die beiden ersten haben nicht einmal einen Zustand und bei ``print_to_file.print(…)`` sieht man an den Namen schon, dass da irgendwas faul ist. `print_to_file()` wäre schon ein sinnvoller Name für die Tätigkeit die da ausgeführt wird.

Aber erst einmal zu den ersten beiden ”Klassen” die gar keine Methoden enthalten sondern jeweils nur eine Funktion. Die kann man auch einfach als das schreiben, als Funktion:

Code: Alles auswählen

def _windows_save(document):
    destination = Path.home() / "Documents" / "scan.txt"
    print("Saving to: ", destination)
    destination.write_text(document, encoding="utf-8")


def _linux_save(document):
    destination = Path.home() / "scan.txt"
    print("Saving to: ", destination)
    destination.write_text(document, encoding="utf-8")
Dann kann man einfach aufgrund von `platform.system()` auswählen welche davon aufgerufen werden soll. Und das muss man auch nicht mit einer Klasse verkomplizieren, sondern kann da einfach *einmal* entscheiden welche der beiden Funktionen unter einem sinnvollen Namen verwendet wird:

Code: Alles auswählen

def _windows_save(document):
    destination = Path.home() / "Documents" / "scan.txt"
    print("Saving to: ", destination)
    destination.write_text(document, encoding="utf-8")


def _linux_save(document):
    destination = Path.home() / "scan.txt"
    print("Saving to: ", destination)
    destination.write_text(document, encoding="utf-8")


save = _linux_save if platform.system() == "linux" else _windows_save

save("Example text.")
Wobei man das noch weiter vereinfachen könnte, da die beiden Funktionen fast das gleiche machen und sich nur durch einen Teilpfad unterscheiden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Hallo.

Ja aber die Namen sind hier nicht wichtig.
Also zumindest im
Hinblick der Frage wobei ich verstehe was du meinst.
Das sind Beispiele von anderen aus einem Buch und dem Internet. Ob die Variabelnamen etc passend sind ist, zumindest für mich gerade uninteressant.
Mir geht es explizit um meine Frage ob ich das richtig sehe oder das windows = WindowsMy…. doch entscheidend ist.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Dann probiere es doch mal aus?
Das schöne an Python ist, dass man Dinge im interaktiven Interpreter einfach testen kann.
Und ich finde, ich habe dir schon eine sehr ausführliche Antwort gegeben.

Weil es nicht nur diese Frage beantwortet sondern auch gewisse Stolpersteine anspricht, muss dieser Abschnitt des Tutorials gelesen sein.
Benutzeravatar
andie39
User
Beiträge: 152
Registriert: Dienstag 7. Dezember 2021, 16:32

Hab ich. Das = muss nicht sein.
Antworten