Hallo,
ich unterrichte fachfremd Informatik und scheitere an dieser Aufgabe, für die ich leider keine Lösung habe. Ich habe schon gegoogelt und ausprobiert, aber bin nicht zum Ziel gekommen.
Freiwillige Knobel - Challenge:
Schaffen Sie es, die Funktion hallo() so zu erweitern, dass es eine Zählvariable gibt, die bei jedem Aufruf der Funktion um den Wert 1 erhöht wird und die dazu benutzt wird, als neue Ausgabe „Hallo Nutzer 1“, „Hallo Nutzer 2“ etc. zu erzeugen?
Beispiel:
1 # Hier ist die Funktion:
2 def hallo():
3 print("Hallo miteinander!")
4
5 # Hier beginnt das Hauptprogramm:
6 hallo()
7 hallo()
8 hallo()
Datei: L2_5_1_1_funktion_ohne_parameter.py
Viele Grüße
Anfängerfrage - Zählvariable
Wer hat denn diese Aufgabe gestellt? Sie zu loesen ist an sich nicht schwer, aber laeuft auf dem aktuellen Lernstand auf die Nutzung einer globalen Variablen hinaus. Und das ist ein Konzept, das man genau NICHT verwenden sollte, und als Anfaenger erst gar nicht ueben. Ich wuerde das also ignorieren. Und in Frage stellen, wie gut das Kursmaterial ist.
Die Aufgabe ist eigentlich nicht ohne die Hilfe von Klassen lösbar, da es einen internen Zustand gibt, der zwischen den Aufrufen erhalten bleiben muß:
Code: Alles auswählen
class Hallo:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
print(f"Hallo Nutzer {self.count}!")
# Hier beginnt das Hauptprogramm:
def main():
hallo = Hallo()
hallo()
hallo()
hallo()
if __name__ == '__main__':
main()
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Unter Ausnutzung das Defaultwerte nur einmal, beim Ausführen der ``def``-Anweisung erstellt werden:
Code: Alles auswählen
#!/usr/bin/env python3
from itertools import count
def hallo(counter=count(1)):
print(f"Hallo Nutzer {next(counter)}")
def main():
hallo()
hallo()
hallo()
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Ja klar ist das eine globale Variable/globaler Zustand und damit keine gute Idee. Würde da auch nichts anderes behaupten. Die Aufgabe verlangt aber danach. Und so wie die Aufgabenstellung den Dateinamen vorgibt, wird das sehr wahrscheinlich automatisiert überprüft, das heisst mit der besseren Lösung von Sirius3 wird man da nicht durchkommen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Hier noch eine Möglichkeit. Die Sinnhaftigkeit sei dahin gestellt. Ist eher grenzwertig.
Code: Alles auswählen
# Hier ist die Funktion:
def hallo(counter=[1]):
print(f"Hallo Nutzer {counter[0]}")
counter[0] += 1
# Hier beginnt das Hauptprogramm:
hallo()
hallo()
hallo()
Code: Alles auswählen
Hallo Nutzer 1
Hallo Nutzer 2
Hallo Nutzer 3
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@__deets__: Mir ging's da weniger um kreativ globalen Zustand zu verschleiern sondern mehr darum den globalen Zustand wenigstens nicht ”frei” auf Modulebene herum liegen zu haben wo man nicht weiss von wo aus der alles geändert werden könnte. So ist er wenigstens an das Funktionsobjekt gebunden und man kommt von aussen nicht ohne Magie (`__defaults__`) heran, die man in normalen Programmen eher nicht verwendet.
Die klassische funktionale Lösung mit Closure:
Die klassische funktionale Lösung mit Closure:
Code: Alles auswählen
#!/usr/bin/env python3
def make_counting_greeter():
counter = 0
def counting_greeter():
nonlocal counter
counter += 1
print(f"Hallo Nutzer {counter}")
return counting_greeter
hallo = make_counting_greeter()
def main():
hallo()
hallo()
hallo()
if __name__ == "__main__":
main()[code]
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Einer geht noch…
Code: Alles auswählen
#!/usr/bin/env python3
from functools import partial
from itertools import count
hallo = partial(
next, (print(f"Hallo Nutzer {counter}") for counter in count(1))
)
def main():
hallo()
hallo()
hallo()
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Hm, würde da das Verändern des Default-Wertes schon darunter fallen‽
Oder muss ich dafür tatsächlich an den Bytecode ran? 
Code: Alles auswählen
#!/usr/bin/env python3
def hallo(counter=1):
hallo.__defaults__ = (hallo.__defaults__[0] + 1,)
print(f"Hallo Nutzer {counter}")
def main():
hallo()
hallo()
hallo()
if __name__ == "__main__":
main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Code zu patchen ist ganz schön kompliziert:
Ich werfe noch Decoratoren in den Ringe:
Code: Alles auswählen
from types import CodeType
def patch(func, old_value, new_value):
fn_code = func.__code__
consts = fn_code.co_consts
consts = tuple(new_value if c is old_value else c for c in consts)
func.__code__ = CodeType(fn_code.co_argcount,
fn_code.co_kwonlyargcount, fn_code.co_nlocals,
fn_code.co_stacksize, fn_code.co_flags, fn_code.co_code,
consts, fn_code.co_names, fn_code.co_varnames,
fn_code.co_filename, fn_code.co_name, fn_code.co_firstlineno,
fn_code.co_lnotab, fn_code.co_freevars, fn_code.co_cellvars,
)
def hallo():
text = "Hallo Nutzer 1"
print(text)
first, second = text.rsplit(' ',1)
patch(hallo, text, f"{first} {int(second)+1}")
Code: Alles auswählen
def count_decorator(func):
func.counter = 0
def wrapper():
func.counter += 1
return func(func.counter)
return wrapper
@count_decorator
def hallo(counter):
print(f"Hallo Nutzer {counter}")
Stark inspiriert durch einen 15 Jahre alten Thread hier aus dem Forum könnte man auch so etwas versuchen:
Ähnelt etwas __blackjacks__ erstem Vorschlag, jedoch mit dem angesprochenen Nachteil, dass man noch leichter von außen dran kommt.
Code: Alles auswählen
In [1]: def hallo():
...: result = getattr(hallo, 'i', -1)
...: setattr(hallo, 'i', result+1)
...: print("Hallo Nutzer", hallo.i)
...:
In [2]: hallo()
Hallo Nutzer 0
In [3]: hallo()
Hallo Nutzer 1
In [4]: hallo()
Hallo Nutzer 2
Ich würde da auf itertools.count() zurückgreifen und stumpf eine globale Variable anlegen:
Der Zugriffsschutz vor möglichen Änderungen von außen spielt für mich keine Rolle, oder sind wir hier bei Java...? 
Code: Alles auswählen
from itertools import count
_user_counter = count(1)
def hallo():
print(f"Hallo Nutzer {next(_user_counter)}")

- __blackjack__
- User
- Beiträge: 14051
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@snafu: Das ist IMHO keine Frage des Zugriffsschutzes sondern das man wenn es auf Modulebene ist, das ganze Programm im Blick haben muss um am Ende zu sehen, dass es nur von dieser einen Funktion verwendet wird. Bei meiner ersten Lösung, so wie ich das wohl auch tatsächlich lösen würde, kommt man ja auch über `__defaults__` an das `count`-Objekt und kann es auch austauschen wenn man will/muss.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
-
- User
- Beiträge: 2
- Registriert: Donnerstag 14. November 2019, 14:57
Hallo nochmal,
danke für die vielen Antworten! Dann werde ich die freiwilige Knobel-Challenge für die Schüler rausnehmen, da es wohl zum jetztigen Zeitpunkt doch zu weit führen würde.
viele Grüße
danke für die vielen Antworten! Dann werde ich die freiwilige Knobel-Challenge für die Schüler rausnehmen, da es wohl zum jetztigen Zeitpunkt doch zu weit führen würde.
viele Grüße