W odpowiedzi na pytanie o dobre zastosowania zmiennych domyślnych wartości argumentów, przedstawiam następujący przykład:
Zmienna wartość domyślna może być przydatna do programowania łatwych w użyciu, możliwych do zaimportowania poleceń własnego autorstwa. Zmienna domyślna metoda sprowadza się do posiadania prywatnych, statycznych zmiennych w funkcji, którą można zainicjować przy pierwszym wywołaniu (bardzo podobnie do klasy), ale bez konieczności uciekania się do zmiennych globalnych, bez konieczności używania opakowania i bez konieczności tworzenia instancji obiekt klasy, który został zaimportowany. Jest na swój sposób elegancki, na co mam nadzieję, że się zgodzisz.
Rozważ te dwa przykłady:
def dittle(cache = []):
from time import sleep
if type(cache) != list or cache !=[] and (len(cache) == 2 and type(cache[1]) != int):
print(" User called dittle("+repr(cache)+").\n >> Warning: dittle() takes no arguments, so this call is ignored.\n")
return
if not cache:
print("\n cache =",cache)
print(" Initializing private mutable static cache. Runs only on First Call!")
cache.append("Hello World!")
cache.append(0)
print(" cache =",cache,end="\n\n")
cache[1]+=1
outstr = " dittle() called "+str(cache[1])+" times."
if cache[1] == 1:outstr=outstr.replace("s.",".")
print(outstr)
print(" Internal cache held string = '"+cache[0]+"'")
print()
if cache[1] == 3:
print(" Let's rest for a moment.")
sleep(2.0)
print(" Wheew! Ready to continue.\n")
sleep(1.0)
elif cache[1] == 4:
cache[0] = "It's Good to be Alive!"
if __name__ == "__main__":
for cnt in range(2):dittle()
print(" Attempting to pass an list to dittle()")
dittle([" BAD","Data"])
print(" Attempting to pass a non-list to dittle()")
dittle("hi")
print(" Calling dittle() normally..")
dittle()
print(" Attempting to set the private mutable value from the outside.")
dittle([" I am a Grieffer!\n (Notice this change will not stick!)",-7])
print(" Calling dittle() normally once again.")
dittle()
dittle()
Jeśli uruchomisz ten kod, zobaczysz, że funkcja dittle () internalizuje się przy pierwszym wywołaniu, ale nie przy dodatkowych wywołaniach, używa prywatnej statycznej pamięci podręcznej (zmienna wartość domyślna) do wewnętrznej pamięci statycznej między wywołaniami, odrzuca próby przejęcia pamięć statyczna jest odporna na złośliwe dane wejściowe i może działać w oparciu o warunki dynamiczne (w tym przypadku na temat liczby wywołań funkcji).
Klucz do używania mutable defaults nie robi niczego, co spowoduje ponowne przypisanie zmiennej w pamięci, ale zawsze zmienia zmienną w miejscu.
Aby naprawdę zobaczyć potencjalną moc i użyteczność tej techniki, zapisz ten pierwszy program w bieżącym katalogu pod nazwą „DITTLE.py”, a następnie uruchom następny program. Importuje i wykorzystuje nasze nowe polecenie dittle () bez konieczności zapamiętywania jakichkolwiek kroków ani programowania przeskakiwania tamborków.
Oto nasz drugi przykład. Skompiluj i uruchom to jako nowy program.
from DITTLE import dittle
print("\n We have emulated a new python command with 'dittle()'.\n")
dittle()
dittle()
dittle()
dittle()
dittle()
Czy to nie jest tak gładkie i czyste, jak to tylko możliwe? Te zmienne wartości domyślne mogą naprawdę się przydać.
========================
Po chwili zastanowienia się nad moją odpowiedzią nie jestem pewien, czy zrobiłem różnicę między używaniem domyślnej metody mutowalnej a zwykłym sposobem osiągania tego samego.
Zwykłym sposobem jest użycie funkcji możliwej do zaimportowania, która otacza obiekt klasy (i używa funkcji globalnej). Dla porównania, tutaj metoda oparta na klasach, która próbuje zrobić to samo, co domyślna metoda mutowalna.
from time import sleep
class dittle_class():
def __init__(self):
self.b = 0
self.a = " Hello World!"
print("\n Initializing Class Object. Executes on First Call only.")
print(" self.a = '"+str(self.a),"', self.b =",self.b,end="\n\n")
def report(self):
self.b = self.b + 1
if self.b == 1:
print(" Dittle() called",self.b,"time.")
else:
print(" Dittle() called",self.b,"times.")
if self.b == 5:
self.a = " It's Great to be alive!"
print(" Internal String =",self.a,end="\n\n")
if self.b ==3:
print(" Let's rest for a moment.")
sleep(2.0)
print(" Wheew! Ready to continue.\n")
sleep(1.0)
cl= dittle_class()
def dittle():
global cl
if type(cl.a) != str and type(cl.b) != int:
print(" Class exists but does not have valid format.")
cl.report()
if __name__ == "__main__":
print(" We have emulated a python command with our own 'dittle()' command.\n")
for cnt in range(2):dittle()
print(" Attempting to pass arguments to dittle()")
try:
dittle(["BAD","Data"])
except:
print(" This caused a fatal error that can't be caught in the function.\n")
print(" Calling dittle() normally..")
dittle()
print(" Attempting to set the Class variable from the outside.")
cl.a = " I'm a griefer. My damage sticks."
cl.b = -7
dittle()
dittle()
Zapisz ten program oparty na klasie w swoim bieżącym katalogu jako DITTLE.py, a następnie uruchom następujący kod (taki sam jak wcześniej).
from DITTLE import dittle
dittle()
dittle()
dittle()
dittle()
dittle()
Porównując te dwie metody, korzyści wynikające z używania zmiennego ustawienia domyślnego w funkcji powinny być wyraźniejsze. Zmienna domyślna metoda nie wymaga zmiennych globalnych, jej zmiennych wewnętrznych nie można ustawić bezpośrednio. I chociaż metoda mutowalna zaakceptowała przekazany przez wiedzę argument dla pojedynczego cyklu, a następnie zlekceważyła go, metoda Class została trwale zmieniona, ponieważ jej zmienne wewnętrzne są bezpośrednio widoczne na zewnątrz. Którą metodę łatwiej zaprogramować? Myślę, że zależy to od Twojego komfortu z metodami i złożonością celów.