• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Python - Czemu taki jest wynik?

Object Storage Arubacloud
0 głosów
444 wizyt
pytanie zadane 14 sierpnia 2018 w Python przez DeBos123 Nałogowiec (44,950 p.)

Witam, znalazłem przypadkiem w python'ie moim zdaniem nietypową rzecz, mianowicie ten kod:

def a(b=[]):
    b.append(0)
    print(b)

a()
a()
a()

przy każdym wywołaniu funkcji wypisuje coraz większą tablicę zer.

Dlaczego taki jest wynik jeżeli zmienna 'b' jest lokalna, czyli powinna być 'resetowana' przy każdym wywołaniu funkcji.

Dla przykładu 'ten sam' kod w ruby'im wypisuje zawsze tablicę z jednym zerem.

Gdzie w takim razie jest ten prawidłowy wynik? W python'ie czy ruby'im?

3 odpowiedzi

+1 głos
odpowiedź 14 sierpnia 2018 przez izonik Stary wyjadacz (12,560 p.)
wybrane 14 sierpnia 2018 przez DeBos123
 
Najlepsza

Spróbuje wytłumaczyć w prosty sposób.
 

Python ładuję funkcję i wartość domyślną tylko raz do pamięci.

 

Później te zera są dodawane do listy utworzonej podczas ładowania funkcji. Lista jest po prostu definiowana tylko raz.

 

Może użyj http://pythontutor.com/visualize.html to bardzo fajna strona, gdzie można zobaczyć, jak python zarządza pamięcią.

 

Co do porównania z Ruby'im , wynika to z tego jak python zarządza pamięcią i różnic w tym temacie pomiędzy tymi (rzekomo) podobnymi językami.

Aby w python'ie uzyskać taki wynik o jaki Ci chodzi możesz użyć tego kodu.

def a(b=None):
    if b is None:
        b = []
    b.append(0)
    print(b)


a()
a()
a()

Jest to tylko przykład, metod jest więcej.

 

Nie umiem dobrze tłumaczyć, ale się starałem. Jak coś będzie nie jasne, napisz.

Pozdrawiam.

+1 głos
odpowiedź 14 sierpnia 2018 przez mokrowski Mędrzec (155,460 p.)

 
class X:
    def __init__(self):
        print("X: Robią mnie!", hash(self))

    def append(self, value):
        print("X: Dodawanko...", hash(self))
        return self

    def __del__(self):
        print("X: Ginę...", hash(self))

def fun(a = X()):
    a.append(0);

if __name__ == '__main__':
    # Linie poniżej odkomentuj w dowolnej konfiguracji...
    #fun()
    #fun()
    #fun(X())
    #del fun
    pass
    print("Oto koniec!")

Wniosek? Argument domyślny jest tworzony w trakcie definiowania funkcji i będąc referencją nie zostanie zerwany przez GC jeśli funkcja istnieje.

Usuń komentarze i pobaw się... 

komentarz 14 sierpnia 2018 przez DeBos123 Nałogowiec (44,950 p.)
Da się coś zrobić, żeby GC (najlepiej automatycznie) czyścił/resetował wszystkie zmienne z tej funkcji po jej wywołaniu?
komentarz 14 sierpnia 2018 przez adrian17 Ekspert (344,860 p.)

Odpowiedź ma jest poprawna, ale nie ma w tym przypadku bezpośredniego związku z GC - po prostu obiekt istnieje i nie przestanie istnieć, póki jest argumentem domyślnym ten funkcji.

Da się coś zrobić, żeby GC (najlepiej automatycznie) czyścił/resetował wszystkie zmienne z tej funkcji po jej wywołaniu?

Niestety to pytanie ma dość mało sensu, ale nie za bardzo potrafię dobrze wytłumaczyć dlaczego :/

Ogólnie, GC to mocno szczegół implementacyjny i nie trzeba o nim wiedzieć przy mówieniu o semantyce języka i nie ma na nią wpływu.

W każdym razie standardowym sposobem ominięcia tego w Pytonie jest:

def a(b=None):
    if b is None:
         b = []
    # reszta kodu

 

komentarz 14 sierpnia 2018 przez DeBos123 Nałogowiec (44,950 p.)

Niestety to pytanie ma dość mało sensu, ale nie za bardzo potrafię dobrze wytłumaczyć dlaczego :/

Chodziło mi w tym pytaniu o to czy da się zrobić coś, żeby po wywołaniu funkcji, wszystkie obiekty, które są z nią związane były w jakiś sposób resetowane. Nie wiem jak to w inny sposób wytłumaczyć. 

komentarz 14 sierpnia 2018 przez adrian17 Ekspert (344,860 p.)
Z tego co wiem, nie (a przynajmniej nie bez jakiejś dużej ilości inspekcji funkcji/metaprogramowania).

Na dole mojej odpowiedzi masz przykład, jak  zazwyczaj to się robi.
komentarz 14 sierpnia 2018 przez mokrowski Mędrzec (155,460 p.)
Eh... zastanawiam się czy autor pytania potrzebuje kompletnej odpowiedzi jeśli te uproszczone (także moja) mu wystarczają. Dość że pełna odpowiedź to sięgnięcie do pojęć mutable/immutable type jeśli chodzi o obiekty domyślne oraz first-class function. Z pojęciem tożsamości (identity) wartości typu zaś będzie dość ściśle wiązało się działanie GC. Z kolei "zapamiętanie wartości" także w ten sposób (przez arg. domyślny), tworzy domknięcie (closure).

Proponuję zapoznać się z dekoratorami to trochę może rozjaśni temat i pokaże że takie działanie wcale nie jest takie toksyczne w każdym przypadku. Dość że pytanie o "resetowanie GC" okaże się wtedy... bez związku.
komentarz 14 sierpnia 2018 przez DeBos123 Nałogowiec (44,950 p.)

W tym przypadku uproszczona odpowiedź mi wystarczy, ponieważ w większości piszę w ruby'im, ale pisząc mały skrypt w python'ie natrafiłem na to o co tutaj zapytałem.

Kiedyś jak pisałem więcej w python'ie to po prostu nie rzuciło mi się tak bardzo w oczy i pomyślałem teraz, że to nie powinno tak być.

"resetowanie GC"

 Nie pisałem nic o restowaniu samego GC, tylko o tym, żeby to właśnie GC 'zresotował' te zmienne.

0 głosów
odpowiedź 14 sierpnia 2018 przez NIMuser Stary wyjadacz (11,030 p.)
W rubym i pythonie podejście jest nieco inne i niestety trzeba znać niuanse różnych języków.
2
komentarz 14 sierpnia 2018 przez Aisekai Nałogowiec (42,190 p.)
Slabe wytłumaczenie, brzmi to mniej więcej tak: "Są różne, bo python się różni od Ruby".

Właśnie kolega się pyta, w czym tkwi ta różnica.

Ps: Ja nie odpowiem, bo nie znam ani tego języka ani tego.

Podobne pytania

0 głosów
0 odpowiedzi 55 wizyt
pytanie zadane 8 lipca 2023 w Ruby przez whiteman808 Obywatel (1,820 p.)
0 głosów
3 odpowiedzi 2,005 wizyt
pytanie zadane 25 marca 2016 w Python przez NTXFN Gaduła (3,430 p.)
+1 głos
1 odpowiedź 416 wizyt

92,576 zapytań

141,426 odpowiedzi

319,652 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...