Leere Argumente, Default Argumente

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
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

Hallo Zusammen,

ich habe folgenden Code:

Code: Alles auswählen

class Class1():
    
    def addition(x,y):
        return x+y
    
class Class2():
    
    def addition(x,y,z):
        return x+y+z
    
class Class3():
    
    def function(Class,x,y,z):
        return Class.addition(x,y,z)
        
Ich möchte die Class3 so schreiben, dass je nach der den Eingabeargumenten entweder die Class1 oder Class1 mit addition() aufgerufen wird.
Das Funktion so auch prima für Class2, allerdings nicht bei Class1 da ein Argument fehlt.

Folgender Aufruf funktioniert nicht:

Code: Alles auswählen

print(Class3.function(Class1,1,1))
Es wird folgender Fehler ausgegeben:

Code: Alles auswählen

TypeError: function() missing 1 required positional argument: 'z'
Wie kann ich dieses Problem fixen ?

Liebe Grüße
TobiM
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TobiM: Bitte richtigen Code zeigen, nicht irgend etwas. Oder falls das tatsächlich der echte Code sein sollte: Lern den Umgang mit Klassen, denn man will ziemlich sicher keine Funktionen in Klassen haben und das erste Argument anders als `self` nennen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

Hallo,

Ich komme von Java und konnte mich mit self noch nicht so richtig anfreunden.

Der "echte" Code is zu unübersichtlich, weshalb ich einige Attribute gelöscht habe und das ganze einwenig reduziert habe. Das Problem und der Fehler bleibt der gleiche.

Die Funktion im echten Code ist __init__() und hat bei den beiden Klassen eine unterschiedliche Anzahl an Argumenten.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TobiM: Was heisst Du konntest Dich mit `self` noch nicht ”anfreunden”? Ohne `self` sind Deine Klassen keine Klassen sondern einfach nur missbräuchliche Verwendung als Namensraum für Funktionen. Da fragt man sich ja fast ob Du in Java auch versuchst etwas anderes als Java zu programmieren.

Dein Code muss mindestens mal so echt werden dass man an dem sinnvoll das Problem nachvollziehen kann. Du hast da momentan drei Klassen die keine Klassen sind. Die kann man da problemlos aus dem Code raus streichen weil es bei dem Beispiel nur unnötige Indirektionen sind, die mit der Ausnahme nichts zu tun haben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

Alles klar dann versuch ichs so nochmal :

Code: Alles auswählen

class Mensch():
    name = ''
    alter = 0
    def __init__(self, name,  alter):
           self.name = name
           self.alter = alter
           
              
class Angestellter(Mensch):
    firma =''
    
    def __init__(self, name, alter, firma):
           self.name = name
           self.alter = alter
           self.firma = firma
    
 def initialisieren(Klasse, name, alter, firma)
        obj = Klasse(name, alter, firma)
        return obj
 
Mit der Funktion initialisieren() möchte ich eine der beiden Klassen initialisieren und dieses Objekt zurückgeben.

Möchte ich nun Angestellter initialisieren, so funktioniert dies, bei Mensch bekomme ich den Fehler von oben, dass eine Angabe fehlt.

Das passt jetzt hoffentlich so, dass man mein Problem versteht.
Benutzeravatar
Dennis89
User
Beiträge: 1153
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wenn du die Funktion 'initialisieren' so wie sie da steht aufrufst, dann musst du alle vier Argumente übergeben. Dann rufst du deine Klasse 'Mensch' entweder mit drei Argumenten auf, obwohl die Klasse nur zwei Argumente benötigt, oder du übergibst nur zwei Argumente obwohl der Aufruf drei Argumente erwartet. In beiden Fällen erhälst du logischerweise eine Fehlermeldung.

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@TobiM: Du musst schon Python als Python akzeptieren, statt zu versuchen, daraus ein Java mit leicht anderer Syntax zu machen. Attribute, die auf Klassenebene definiert werden, sind Klassenatribute. In deinem Beispiel würde das etwa dazu führen, dass alle Menschen denselben Namen haben. Wenn du Instanzvariablen willst, also dass verschiedene Menschen auch verschiedene Namen haben können, dann solltest du das in der __init__() Methode machen, indem du zB. den gewünschten Namen an self.name bindest, wie du es ja eh schon tust. Fragt sich, warum du das im Namensraum der Klasse nochmal machst.
Zuletzt geändert von pillmuncher am Freitag 19. März 2021, 23:52, insgesamt 2-mal geändert.
In specifications, Murphy's Law supersedes Ohm's.
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@Dennis ganz genau, aber wie kann ich das beheben ?

Ich möchte der Funktioniert initialisieren() auch nur 2 Argumente übergeben können und damit eine Instanz von Mensch erzeugen können.

Bzw. auch nur ein Argument übergeben und so beide initialisieren. Ich kann man fehlende Argumente "ignorieren" ?
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@pillmuncher habe ich das nicht gemacht ?
Wenn man den Konstruktor von Mensch aufruft wird doch ein neuer name festgelegt ?!

Code: Alles auswählen

class Mensch():
    name = ''
    alter = 0
    def __init__(self, name,  alter):
           self.name = name
           self.alter = alter
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

TobiM hat geschrieben: Samstag 20. März 2021, 00:00@pillmuncher habe ich das nicht gemacht ?
Ja, hast du. Aber was meinst du, machen diese Zeilen auf Klassenebene?

Code: Alles auswählen

    name = ''
    alter = 0
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TobiM: Du weisst doch an der Stelle wo Du `initialisieren()` aufrufst sowohl welche Klasse Du am Ende haben willst, denn die übergibst Du ja, als auch das Du bei Mensch ein Argument weniger hast, also ist die Frage warum Du nicht gleich die richtige Klasse mit den Argumenten aufrufst die Du hast und die zu der Klasse passen.

Beschreibe doch mal welches *Problem* hier eigentlich gelöst werden soll und nicht welche Probleme Du mit einer Lösung hast. Vielleicht wollen die Probleme mit dieser Lösung Dir ja auch sagen das die Lösung keine (gute) Lösung für das eigentliche Problem ist.

Wobei ich durch Deine anderen Themen schon den verdacht habe das es an sich schon keine gute Idee war das ganze in eine statische Klassenhierarchie giessen zu wollen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@pillmuncher

Ich denke mal nichts ??
Sobald man eine Instanz erzeugt werden die Attribute überschrieben oder sehe ich das falsch ?
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@pillmuncher ich habe das Problem verstanden. Ich habe hier Klassen- mit Objektvariabeln vertauscht, dachte man muss die Attribute iwie zuerst initialisieren, aber das macht kein Sinn und muss weg.


@__blackjack__ mein eigentliches Problem besteht darin, dass ich eine Datenbank habe die mittels ORM mit einer statischen Klassenhierarchie verbunden ist. In die Datenbank möchte ich nun Instanzen verschiedener Klassen schreiben, dazu habe ich eine Funktion add(), die ein Datentyp (Klasse) und die entsprechenden Attribute nimmt und daraus einen Eintrag erstellen soll. Solange alle Klassen die gleiche Anzahl an Attributen haben klappt dass, allerdings nicht wenn die Anzahl wie oben abweicht.

Ich hätte dazu gerne eine Funktion add(Klasse, arg1,arg2,arg3,...) die eine Instanz einer beliebigen Klasse in die Datenbank schreibt, ohne mich auf einen Datentyp/Klasse festlegen zu müssen. Dabei wird natürlich ein Fehler bei Zuviel Input ausgegeben, allerdings soll bei Zuwenig Input leere Felder bzw. default Werte verwendet werden.

Mit der oberen Struktur will ich mir, durch die Klassen, neue Datentypen für Objekte erschaffen, die ich dann in einer Datenbank ablege. Bei der weiteren Verarbeitung erhoffe ich mir durch die Klassenstruktur eine einfacheres Handling.

Ich hoffe, dass hilft nun weiter.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@TobiM: was Du eigentlich möchtest, ist eine save-Methode auf den Klassen. Wenn Du ein ORM verwendest, sollten Dir die passenden Klassen bereits zur Verfügung stehen.
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@kbr ja genau, allerdings habe ich ja dann wieder das gleiche Problem, dass bei verschiedenen Klassen, bei denen die Anzahl der Attribute nicht übereinst ein Fehler geworfen wir.
Gibt es da keinen Formalisnus sowas zu ignorieren?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Zeig doch einfach den Code wie er wirklich ist, insbesondere die Stelle, wo du `initialisieren` aufrufst.
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

Ich habe einmal eine base Datei, ehrlich gesagt keine Ahnung wofür ich die genau brauche, aber es wurde nicht in der Hauptdatei akzeptiert.

Code: Alles auswählen

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

# ORM and Db Connection
engine = create_engine('postgresql://postgres:passwort1234@localhost:5432/test', echo=False)
Session = sessionmaker(bind=engine)
Base = declarative_base()
Dann die Hauptdatei, hierbei habe ich für bessere Lesbarkeit Klassennamen und Attribute leicht verändert:

Code: Alles auswählen


#Imports
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy.orm import mapper
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Column, String, Integer, Date
from base import Base


#Class Hierachy
class Lebewesen(Base):
    __tablename__ = 'Tierwelt'
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    maximalKraft = Column(Integer)
    alter = Column(Integer)
    type = Column(String(150))
    
    __mapper_args__ = {
        'polymorphic_identity':'Lebewesen',
        'polymorphic_on':type
    }
    
class Tier(Lebewesen):
    __mapper_args__ = {'polymorphic_identity':'Tier'}
    
    
class Hund(Tier):
    anzahlPfoten = Column(Integer)
    __mapper_args__ = {'polymorphic_identity':'Hund'}
    

class Labrador(Hund):  
    __mapper_args__ = {'polymorphic_identity':'Labrador'}
    
    
    #Konsturtor, alle default auf none
    def __init__(self ,id , name = none, maximalKraft = none, alter = none, anzahlPfoten = none):
        self.id = id
        self.name = name
        self.maximalKraft = maximalKraft 
        self.alter = alter 
    	self.anzahlPfoten = anzahlPfoten 
    
class Katze(Lebewesen):
    __mapper_args__ = {'polymorphic_identity':'Katze'}
    
class LanghaarKatze(Katze):
    __mapper_args__ = {'polymorphic_identity':'LanghaarKatze'}

    haarlaenge= Column(Integer)
    hight = Column(Integer)
    
    #Konstruktor
    def __init__(self ,id , name = none, maximalKraft = none, alter = none, haarlaenge = none, hight  = none  ):
        self.id = id
        self.name = name
        self.maximalKraft = maximalKraft 
        self.alter = alter 
        self.haarlaenge = haarlaenge 
        self.hight  = hight  


#Warum brauch ich das hier nochmal, kommt das nicht von base ? 
engine = create_engine('postgresql://postgres:passwort1234@localhost:5432/test', echo=False)
Session = sessionmaker(bind=engine)
sess = Session()

#Auch hier sind die Inputs default auch none, weil ich hoffte dass es das Problem löst
def add_entry(Klasse, id , name = none, maximalKraft = none, alter = none, anzahlPfoten = none, haarlaenge = none, hight  = none):
    obj = Klasse( id , name , maximalKraft , alter , anzahlPfoten , haarlaenge , hight )
    sess.add(obj)
    sess.commit()
    sess.close()
Beim austesten:

Code: Alles auswählen

#Dieser Aufruf funktioniert nicht, da zuviele Argumente übergeben wurden: Fehler: __init__() takes from 1 to 6 positional arguments but 7 were given
add_entry(LanghaarKatze, 1, 'Fluff', 5, 12, 3, 20)

#Dieser Aufruf nicht funktioniert, da zuviele Argumente übergeben wurden: Fehler: __init__() takes from 1 to 5 positional arguments but 7 were given
add_entry(Labrador, 2, 'Bello', 15, 3, 4)

Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@TobiM: In dem Modul wo die `Base` definiert wird sollte `engine` nicht auf Modulebene definiert werden. Das importieren eines Moduls sollte keine Seiteneffekte haben, schon gar nicht das eine Datenbankverbindung geöffnet wird. Ich verstehe auch nicht warum Du das in dem anderen Modul noch mal machst. Das gibt es auch in `base`, da hättest Du das also auch her holen können wie Du das mit `Base` ja auch machst. Aber wie gesagt, das sollte nirgends einfach durch das reine importieren des Moduls passieren.

Die `Base`-Klasse sorgt dafür, dass all die davon abgeleiteten Klassen die ”Magie” besitzen durch Klassenattribute so etwas wie ”Deklarationen” zu erlauben.

Das Schliessen der Sitzung gehört sicher nicht in die `add_entry()`-Methode. Und ich frage immer noch warum Du das Objekt auf so eigenartige Weise *in* der Funktion erzeugen musst/willst, und das nicht einfach *vorher* machst. Du hast alle Informationen.

Die Funktion sollte dann so aussehen:

Code: Alles auswählen

def add_entry(session, obj):
    session.add(obj)
    session.commit()
Und die aufrufe dann so:

Code: Alles auswählen

    add_entry(session, LanghaarKatze(1, "Fluff", 5, 12, 3, 20))
    add_entry(session, Labrador(2, "Bello", 15, 3, 4))
Einfach, lesbar, verständlich, keine Magie nötig.

Anmerkungen: Du beziehst Dich in dem Modul auf `none`, das sollte wohl jedes mal `None` heissen.

`__init__()` ist kein Konstruktor sondern eine Initialisierung. Der Konstruktor heisst in Python `__new__()` und wird nur sehr selten verwendet. An der Stelle ist dann eigentlich immer etwas ”magisches” wenn man von der normalen Objekterstellung abweichen will.

Ich sehe auch den Sinn nicht wirklich, denn `Base` sorgt schon für eine `__init__()`. Ja, da muss man dann die Argumentnamen angeben, aber der Lesbarkeit schadet das ja nicht wenn man auch beim erstellen des Objekts weiss was 5, 12, 3, 20 bei einer Langhaarkatze eigentlich bedeuten sollen.

Zudem ist das eher ungewöhnlich die ID anzugeben, denn genau die ist üblicherweise `None` und wird von der Datenbank vergeben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
TobiM
User
Beiträge: 15
Registriert: Mittwoch 10. März 2021, 09:06

@ __blackjack__ vielen Dank, das hat mir sehr geholfen. Ich werde nun einiges umbauen und hoffe dass danach alles so funktioniert.
Antworten