chevallier hat geschrieben:
Wie kann man logisch an die Sache herangehen? Wieso gehts mal ohne, mal mit Klammern. Ich weiß, das hat etwas damit zu tun, dass Funktionen Objekte sind und man ohne Klammern nur die Objekte aufruft, aber trotzdem blicke ich da nicht durch.
Im Grunde genommen ist das recht einfach und Du hast es ja schon erkannt: Der Name einer Funktion verweist auch nur auf das Funktionsobjekt, genau wie bei anderen Zuweisungen auch (Nicht durch die [zahl] verwirren lassen - das sind nur Anzeigen der Shell IPython!):
Code: Alles auswählen
In [3]: a = 4
In [4]: b = list()
In [5]: c = lambda x: x ** 2
In [7]: def foo():
...: print("foo wurde aufgerufen")
...:
In [8]: d = foo
In [9]: foo
Out[9]: <function __main__.foo>
In [12]: d
Out[12]: <function __main__.foo>
Man spricht auch davon, dass ein Objekt an einen Namen "gebunden" wird. Bei Funktionen passiert das mittels ``def`` auf spezielle Art und Weise. Man kann das aber auch explizit erledigen, wie eben in [8] gezeigt, wo das Funktionsobjekt zusätzlich zum Namen ``foo`` auch an den Namen ``d`` gebunden wird.
Will man eine Funktion (oder Methode oder allgemein: *Callable*) ausführen, so teilt man das dem Interpreter mit, indem man ein rundes Klammernpaar hinter den Namen setzt:
Code: Alles auswählen
In [10]: c(3)
Out[10]: 9
In [11]: d()
foo wurde aufgerufen
Will man ein Funktions*objekt* als Parameter übergeben, so darf man es *nicht* aufrufen, sondern muss den Namen übergeben:
Code: Alles auswählen
In [13]: from operator import add, sub
In [15]: def operate(func, a, b):
....: return func(a, b)
....:
In [16]: operate(add, 2, 1)
Out[16]: 3
In [17]: operate(sub, 2, 1)
Out[17]: 1
So einfach ist das und so ist das auch in Deinen Beispielen. Geh die mal *genau* durch, dann siehst Du, was passiert.
Eine Funktion erzeugen diese beiden Varianten nämlich *nicht* als Rückgabewert, weil jeweils an falscher Stelle der Funktionsaufruf erfolgt!