Optionale 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
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Ich hab das schon bei einigen Funktionen bemerkt, weiß aber nicht wie ich sowas für meine eigenen Funktionen machen kann:

fkt ( a [, b ] )

So sieht es aus, aber wenn ich es einfach nach diesem Muster abschreibe bekomme ich eine Fehlermeldung.
Kann mir jemand sagen, wie ich sowas machen kann?
XT@ngel
User
Beiträge: 255
Registriert: Dienstag 6. August 2002, 14:36
Kontaktdaten:

Du musst der Variable schon bei erstellung der Funktion einen Wert zuweisen

Code: Alles auswählen

def meine_Funktion(a, b=1):
	print a + b
oder

Code: Alles auswählen

def func (a, b=None):
	if b == None:
		print "Nur a wurde übergeben"
	else:
		print a, b
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Kommt im Endeffekt wohl auf das Selbe raus, aber dann sehe ich die eckigen Klammern nicht, sondern bekomme genau das angezeigt, was auch in der Funktionsdefinition steht....
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Hallo!
Kartoffel hat geschrieben:fkt ( a [, b ] )
Das hast Du aber garantiert nicht in ausführbarem Code gesehen, sondern nur in der Dokumentation der Funktion. Die eckigen Klammern informieren nur den Leser der Doku darüber, dass das innerhalb der eckigen Klammern optional ist.

Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Ich habs in der Dokumentation gelesen und in der info die in IDLE angezeigt wird, wenn ich in der Klammer eines Funktionsaufrufs bin. (zeigt die Parameter an, die man der Fkt. übergeben kann)

Ist mir bis jetzt nur in built-in-Funktionen aufgefallen, außerdem ist noch eine Besonderheit dabei:

Bei f(a[,b[,c]]) kann man beispielsweise c nur eingeben, wenn man auch b eingegeben hat.
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Kartoffel hat geschrieben:Bei f(a[,b[,c]]) kann man beispielsweise c nur eingeben, wenn man auch b eingegeben hat.
Ja, das ist noch eindeutig. Nutzt man die 'äußere' Option, so ist b Pflicht und c wiederum optional. Ließe sich beliebig verschachteln.

Bei aber zum Beispiel range([start,] stop[, step]) ist Schluss mit Logik. Man sieht zwar, dass "start" und "step" optional sind, aber nicht, dass bei Angabe von "step" zwingend "start" angegeben sein muss. Die Notation mit den eckigen Klammern hat also auch so ihre Grenzen.

Jan
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Kartoffel hat geschrieben:Bei f(a[,b[,c]]) kann man beispielsweise c nur eingeben, wenn man auch b eingegeben hat.
muss ich dir wiedersprechen...

Code: Alles auswählen

>>> def f(a,b=0,c=0):
    print a,b,c
>>> f(1,c=3)
1 0 3
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Milan hat geschrieben:muss ich dir wiedersprechen...
Es ging ja auch eher um die Notation in der Doku. Wenn dort file(filename[, mode[, bufsize]]) steht, musst Du bei der Angabe von 'bufsize' auch zwingend 'mode' angeben. Der Aufruf file("bla.txt",bufsize=1024) funktioniert natürlich nicht, da 'bufsize' ja nicht wirklich ein Bezeichner der Funktion file() ist.
Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Milan hat geschrieben:
Kartoffel hat geschrieben:Bei f(a[,b[,c]]) kann man beispielsweise c nur eingeben, wenn man auch b eingegeben hat.
muss ich dir wiedersprechen...

Code: Alles auswählen

>>> def f(a,b=0,c=0):
    print a,b,c
>>> f(1,c=3)
1 0 3
Eben, darum ist es ja auch nicht das selbe :?
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Kartoffel hat geschrieben:Eben, darum ist es ja auch nicht das selbe :?
Ich glaub', der Groschen ist noch nicht gefallen ist, oder ;-)?

Eine Funktion die mit f(a[,b[,c]]) dokumentiert wird, könnte als def f(a,b=0,c=0): pass implementiert sein, oder aber auch als def f(a,*args): pass.
Die eckigen Klammen sind keine Python-Syntax, sondern nur eine übliche Art, in Beschreibungen von Funktionen/Methoden (also nur in der Doku) optionale Argumente als solche kenntlich zu machen.
Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Bist du dir da sicher?

Nehmen wir zum Beispiel range([start,]stop[,step])
wenn ich ihm nur ein Argument übegebe, ist es stop.

Wenn ich das als def range(start=None, stop, step=None): definieren würde, würde ich schon bei der Definition einen Syntax-Error bekommen.

Ausserdem kann ich die Sache mit den verschactelten eckigen Klammern, die ich schon angesprochen habe auch nicht mit einer Standardzuweisung in der Definition erledigen.

Und ich kenne auch keinen Weg, die Anzeige der Dokumentation zu ändern, es sind immer alle Argumente in der ersten und ggf. ein Docstring in der zweiten Zeile.

Wenn du mir das alles erklären kannst, glaube ich dir, versprochen :D
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Wenn ich das als def range(start=None, stop, step=None): definieren würde, würde ich schon bei der Definition einen Syntax-Error bekommen.
Und zwar weil Parameter ohne Defaultwert grundsätzlich nicht hinter Parametern mit Defaultwerten stehen dürfen. Deshalb lässt sich hier diese "Eckige-Klammern-Notation" nicht mit Default-Parametern realisieren. Bei f(a[,b[,c]]) geht es, weil alle optionalen Parameter hinten vereint stehen.
Ausserdem kann ich die Sache mit den verschactelten eckigen Klammern, die ich schon angesprochen habe auch nicht mit einer Standardzuweisung in der Definition erledigen.
In der Doku: f(a[,b[,c]]) Implementiert als: def f(x,y=0,z=0): pass
Geht doch wunderbar: Der Anwender der Funktion erkennt anhand der eckigen Klammern, dass er die Funktion mit z.B. f(6), f(6,1) oder f(6,1,4) aufrufen kann. Die Implementation spielt da mit. def f(x,*args): pass hätte aber auch funktioniert.
Und ich kenne auch keinen Weg, die Anzeige der Dokumentation zu ändern, es sind immer alle Argumente in der ersten und ggf. ein Docstring in der zweiten Zeile.
Darum geht's Dir! Sorry, das war mir nicht klar. Also, bei den string-Funktionen ist das einfach so gelöst, dass der 1. Doc-String eben die "Eckige-Klammer-Notation" enthält.

Code: Alles auswählen

# Join fields with optional separator
def join(words, sep = ' '):
    """join(list [,sep]) -> string

    ...
    """
    return sep.join(words)
Es wird allerdings auch die tatsächliche Parameterliste angezeigt, hier also (words, sep = ' '). Ist nicht so schön. Bei BuildIns dagegen wird nur der Doc-String angezeigt.
Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

So ganz bin ich immer noch nicht überzeugt:

Dass ich Default-Argumente nicht hinter nicht-Defaults packen darf, weiß ich. Deshalb wundere ich mich ja auch wie das bei range funktioniert.

Bei def f(a, b=None, c=None) kann ich aber auch einen Aufruf f(1, c=2) machen, das geht mit den verschachtelten Klammern nicht.
(Nagut, da könnte ich mir etwas in der Art vorstellen, dass ein Fehler ausgelöst wird, wenn b==None und c!=None)

Der Docstring ist auch gar nicht so wichtig - mich interessiert nur wie man ein entsprechendes Verhalten hinbekommt.
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Hi, ich muss Voges mal Beistand leisten (;)), dass was er sagt stimmt schon. Allgemein werden Funktionen mit begrenzter Anzahl optionaler Parameter so definiert: def f(a=None,b=None,c=None).

bei f(1,c=2) wird nur ein Spezialfall von den Keywordargumenten genutzt, weil es ja einen fest definierten Parameter c gibt. Range dagegen ist ein Sonderfall, es ist eine Builtin-Funktion. Du könntest ein ähnliches Verhalten intern in der Funktion realisieren, beispielsweise so:

Code: Alles auswählen

def my_range(start,stop=None,step=1):
    if stop==None:
        stop=start
        start=0
    ...#jetzt gehts normal weiter...
Zuletzt geändert von Milan am Freitag 27. Juni 2003, 05:26, insgesamt 1-mal geändert.
Voges
User
Beiträge: 564
Registriert: Dienstag 6. August 2002, 14:52
Wohnort: Region Hannover

Kartoffel hat geschrieben:Deshalb wundere ich mich ja auch wie das bei range funktioniert.
Wie es geht, hat Milan gezeigt. range() ist ja BuildIn, so das man sich das nicht angucken kann. Aber in \Lib\random.py gibt es die Funktion randrange([start,] stop[, step]), die so ungefähr implementiert ist.
Der Docstring ist auch gar nicht so wichtig - mich interessiert nur wie man ein entsprechendes Verhalten hinbekommt.
Kannst Du nochmal insich geschlossen erläutern, was Du erreichen möchtest? Vielleicht an einem Beispiel. Im allerersten Beitrag schreibst Du was von einer Fehlermeldung.

Jan
Kartoffel
User
Beiträge: 66
Registriert: Montag 7. April 2003, 17:08

Was konkretes hatte ich eigentlich (noch) nicht vor. Ich wollte nur wissen, wie so eine Funktion aufgebaut ist und wie ich ein Verhalten wie in den Builtins erreiche.

Die Fehlermeldung von der ich am Anfang gesprochen habe, ist die die man bekommt, wenn man versucht eine Funktion mit solchen Eckigen Klammern so zu definieren, wie man es in der Doku der Builtins sieht.

Da ich inzwischen (endlich?) davon überzeugt bin, dass ihr recht habt, hat sich mein Problem schon erledigt.
Antworten