Przekazanie słownika do funkcji

Przekazanie słownika do funkcji
Taumas
  • Rejestracja:prawie 18 lat
  • Ostatnio:3 miesiące
  • Lokalizacja:wlkp
  • Postów:121
0

Witam.
Mam w Python'ie coś takiego:

Kopiuj
def funkcja1():
    d = {'Adam' : ['Monika', 'Kasia'], 'Mariusz' : ['Patrycja', 'Kasia']}

def funkcja2(zm):
    #tutaj chce przekazać słownik

Jak przekazać ten słownik z jednej funkcji do 2-giej?

4

Normalnie. Przez referencję.

vpiotr
Minus za lakoniczność. Jak wygląda referencja w Pythonie?
KU
A jak ma wyglądać? Jak zmienna. Zmienne typów złożonych są referencjami, zatem słowniki przekazuje się normalnie, jako argument funkcji. Mam napisać jak się wywołuje funkcję z argumentem?
msm
Plus bo 1) minus był bez sensu 2) bo odpowiedź jest na poziomie pytania 3) bo tak.
vpiotr
@msm. Uważasz, że to pytanie jest banalne? Dla mnie nie.
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Tu masz odpowiedź:

http://dev.fyicenter.com/Interview-Questions/Python/How_do_I_write_a_function_with_output_parameters.html

Z tego co wiem, to w Pythonie zalecany jest sposób pierwszy.

1
vpiotr napisał(a)

Z tego co wiem, to w Pythonie zalecany jest sposób pierwszy.

Słownik jest typem złożonym. W Pythonie wszystkie zmienne typów złożonych są referencjami. Zwracanie typu złożonego, przekazanego w argumencie (jak pokazuje sposób pierwszy) nie ma większego sensu. To rozwiązanie stosuje się w przypadku typów prostych, które są kopiowane w funkcjach:

Kopiuj
#!/usr/bin/env python                                                                                                                                                                        

def funA(somedict):                                                                                                                                                                          
        print('Dictionary in funA() before change: ' + str(somedict))
        somedict['a'] = 1
        print('Dictionary in funA() after change: ' + str(somedict))


def funB():
        mydict = {'b': 2}
        print('Dictionary in funB() before call: ' + str(mydict))
        funA(mydict)
        print('Dictionary in funB() after call: ' + str(mydict))


def funC(someint):
        print('Integer in funC() before change: ' + str(someint))
        someint += 1
        print('Integer in funC() after change: ' + str(someint))


def funD():
        myint = 1
        print('Integer in funD() before call: ' + str(myint))
        funC(myint)
        print('Integer in funD() after call: ' + str(myint))

funB()
funD()

Wynik:

Kopiuj
Dictionary in funB() before call: {'b': 2}
Dictionary in funA() before change: {'b': 2}
Dictionary in funA() after change: {'a': 1, 'b': 2}
Dictionary in funB() after call: {'a': 1, 'b': 2}
Integer in funD() before call: 1
Integer in funC() before change: 1
Integer in funC() after change: 2
Integer in funD() after call: 1

Z podanego przez Ciebie linka to nr 3 i 4 (które sa tym samym - przekazaniem przez referencję) jest zalecany w przypadku słowników.

vpiotr
No właśnie - szerzysz dezinformację. Nie znam dobrze Pythona, dopiero się go uczę, ale z tego co wiem referencji jako składni (w sensie C++) w Pythonie nie ma - bo wszystkie struktury na wejściu są referencjami. Coś mi się jednak świta, że w jakimś celu przekazuje się argumenty z dwoma znakami z przodu - chyba "@@", ale nie mogę znaleźć przykładu ani opisu po co?
KU
Źle Ci świta. Pojedynczym znakiem '@' z przodu oznacza się dekoratory. Podwójny znak '@' można wstawić w miejscu, w ktrórym chcesz żeby wystąpił błąd składni (możesz też użyć jakiegoś innego znaku, np. '*'). Dezinformacji nie szerzę, gdyż wywołanie funkcji ze zmienną typu złożonego jako argumentem jest przekazaniem przez referencję.
vpiotr
Chyba to co mi świtało to kwargs, czyli coś zupełnie innego: http://programming.itags.org/python/59647/
KU
"keyword arguments" tak, ale to jest co innego.
msm
@vpiotr - jak na razie to ty szerzysz dezinformację i jeszcze coś ci 'świta'... :|
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

OMG, to jest chyba bardziej skomplikowane:

  • argumenty proste są przekazywane przez wartość
  • struktury przez referencję
  • ale listy przez wartość?

http://www.tutorialspoint.com/python/python_functions.htm

1

Nie, lista też jest referencją:

Kopiuj
#!/usr/bin/env python

def funA(somelist):
        print('List in funA() before change: ' + str(somelist))
        somelist.append(1)
        print('List in funA() after change: ' + str(somelist))


def funB():
        mylist = [2, 3]
        print('List in funB() before call: ' + str(mylist))
        funA(mylist)
        print('List in funB() after call: ' + str(mylist))


funB()

Wynik:

Kopiuj
List in funB() before call: [2, 3]
List in funA() before change: [2, 3]
List in funA() after change: [2, 3, 1]
List in funB() after call: [2, 3, 1]
vpiotr
Tak, ale w przykładzie który podałem tę referencję "psują" nową wartością i wtedy już nie jest referencją. Czyli to taka pół-referencja. Nieładnie.
KU
Albo źle się wyraziłeś, albo nie rozumiesz czym jest referencja.
vpiotr
No w Pythonie to najwidoczniej nie rozumiem. Referencja = argument który jeśli zmienię wewnątrz funkcji, zmienia również zmienną podaną jako argument funkcji na zewnątrz. Jak widać w przykładzie z http://www.tutorialspoint.com w Pythonie nie zawsze tak jest.
KU
Nie. Referencja jest "etykietką". W Pythonie działa tak samo jak np. w C++ czy Javie. To nie jest "argument, który zmienia również zmienną". Nie wiem o którym przykładzie z tej strony mówisz, ale referencja w Pythonie zachowuje sie jak każda inna referencja.
iooi
W Javie nie ma referencji.
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Piszę o tym:

Kopiuj
# Function definition is here
def changeme( mylist ):
   "This changes a passed list into this function"
   mylist = [1,2,3,4]; # This would assig new reference in mylist
   print "Values inside the function: ", mylist
   return

# Now you can call changeme function
mylist = [10,20,30];
changeme( mylist );
print "Values outside the function: ", mylist

W jakiej formie referencja w C++ zachowa się tak samo? Tzn nie zmieni się wartość "outside"?

edytowany 1x, ostatnio: vpiotr
0

W komentarzu masz napisane co się dzieje. Tworzysz nową referencję w funkcji.
Może to rozjaśni sytuację:

Kopiuj
#!/usr/bin/env python

def funA(somelist):
        print('List in funA() before append(): ' + str(id(somelist)))
        somelist.append(1)
        print('List in funA() after append(): ' + str(id(somelist)))
        somelist = [4, 5, 6]
        print('List in funA() after assign: ' + str(id(somelist)))


def funB():
        mylist = [2, 3]
        print('List in funB() before call: ' + str(id(mylist)))
        funA(mylist)
        print('List in funB() after call: ' + str(id(mylist)))
        print('Contents: ' + str(mylist))


funB()

Wynik:

Kopiuj
List in funB() before call: 34315944
List in funA() before append(): 34315944
List in funA() after append(): 34315944
List in funA() after assign: 34056312
List in funB() after call: 34315944
Contents: [2, 3, 1]

Pamiętaj, że Python jest językiem dynamicznie typowanym!

Zobacz pozostały 1 komentarz
KU
To nie jest wskaźnik. Nie rozumiesz co się dzieje w funkcji. Przekazujesz referencję w argumencie, a w ciele funkcji tworzysz nową referencję, przykrywając argument. Gdyby istniała możliwość dobrania się do argumentu, to nadal mógłbyś go zmieniać i działałby jak zwykła referencja. W C++ czegoś takiego nie zrobisz, bo kompilator nie zezwala na przykrycie argumentu. To, co Ty robisz to tworzysz nową zmienną (referencję) o takiej samej nazwie jak argument, ale nie niszczysz oryginału. Nie wiem już jak prościej Ci to wytłumaczyć.
vpiotr
Ależ owszem, C++ pozwala na przykrycie argumentu / struktury. Ale tylko jeśli jest przekazywana jako wartość (patrz iteratory) albo jako wskaźnik. Nigdy przez referencję. Nie musisz mi tego tłumaczyć, widzę przecież jako to działa, chodzi mi tylko o nazewnictwo.
KU
No cóż, mój kompilator (g++) nie zezwala ("error: declaration of 'int i' shadows a parameter"), niezależnie od tego czy argument jest przekazywany przez wskaźnik, referencję czy wartość.
vpiotr
Zmień na nowszy model :) A tak serio: void shadowBegin(std::vector<int>::iterator itBegin, std::vector<int>::iterator itEnd) { while(itBegin++ != itEnd) {...} } - wartość itBegin (klasa) zmieniana jest tylko wewnątrz funkcji...
KU
Ale w tej funkcji nigdzie nie przykrywasz itBegin, tylko wywołujesz na nim operator autoinkrementacji. Jakbyś w funkcji miał 'std::string itBegin;', to wtedy byś przykrywał. Chyba, że ja tu czegoś nie widzę (daj kod w nowym wpisie, bo od czytania komentarzy mi się już w oczach troi)...
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0

Przykrywam, tyle że tego dobrze nie widać, może być tak:

Kopiuj
// przykrycie w C++ argumentu przesłanego przez wartość:
void f1(std::vector<int>::iterator itBegin, std::vector<int>::iterator itEnd)
{ 
  if (jestWtorek()) {
    itBegin = itEnd; // przykrycie - zmieniłem lokalną wartość argumentu przesłanego przez wartość, 
   // *itBegin wskazuje na inny element niż na starcie
   // wywołania na itBegin odwołują się teraz do innego elementu
 }

  // cos tam robie z *itBegin
}

// przykrycie w C++ argumentu przesłanego przez wskaźnik:
void f2(char *cBeginPtr, char *cEndPtr)
{ 
   if(jestWtorek()) {
     cBeginPtr = cEndPtr; // przykrycie - zmieniłem lokalną wartość argumentu przesłanego przez wskaźnik, 
     // *cBeginPtr wskazuje teraz na inne miejsce w pamięci
     // zmiana *cBeginPtr nie zmieni zmiennej która była wskazana na początku o ile cBeginPtgr było różne od cEndPtr
  }
}

// referencja - brak przykrycia 
void f3(char &ptr1, char &ptr2)
{ 
   if(jestWtorek()) {
     ptr1 = ptr2; // zmieniłem zawartość zmiennej przekazanej do ptr1, a nie samo na nią wskazanie
  }
}
edytowany 2x, ostatnio: vpiotr
0

Jak już napisałem wcześniej, nie rozumiesz co się dzieje w funkcji.
OK, to korzystając z okazji, że wyskoczyliśmy z komentarzy, odpowiednikiem w języku C++ tego, co Ty robisz w funkcji Pythonowej jest taki kod:

Kopiuj
void  funA(int  i)
{
    int i = 2;
}


int main(void)
{
    int     myint = 1;

    funA(myint);
    return 0;
}

O takie przykrycie mi chodzi. To niestety się nie skompiluje, ale obrazuje o co chodzi z tworzeniem nowej referencji w funkcji Pythonowej. W Pythonie, w funkcji tworzysz nową referencję, która ma taką samą nazwę jak argument. Argument zostaje przykryty (ale dalej sobie istnieje), zaś w funkcji pojawia się nowa zmienna lokalna, do której przypisujesz nową referencję... Mam nadzieję, że teraz zrozumiesz czego nie rozumiesz.

vpiotr
OK, dla mnie jest to jeden wniosek: referencja w Pythonie = wskaźnik w innych językach
KU
Echhh... No właśnie nie jest jak wskaźnik. Gdyby był, to do referencji mógłbyś przypisać inną referencję, a tak się nie da (tak, jak i w przypadku referencji w C++). Każda operacja przypisania typu złożonego tworzy nową referencję. Referencja w Pythonie jest jak referencja w C++. Albo inaczej, referencja jest etykietką, a nie zmienną przypisaną do wirtualnego obszaru pamięci, której zawartość możesz zmieniać. Może tak załapiesz o co mi chodzi.
vpiotr
Wiem o co chodzi, ja to widzę jako wskaźnik do struktury (jego zmiana zmienia wskazanie a nie zawartość obiektu wskazywanego), ale nie będę nikogo na to pojęcie nawracał. To chyba kwestia punktu widzenia.
KU
OK, najwyraźniej nie potrafię tego wytłumaczyć, więc ja już może zakończę. Źle to widzisz. Obawiam się też, że nie rozumiesz czym naprawdę jest referencja (w jakimkolwiek języku), albo najzwyczajniej w świecie nie rozumiem Twojego toku myślenia (albo i jedno i drugie). Proponuję EOT, bo nasze wywody zaczynają się robić nudne i krążyć w kółko. Tak czy siak, powodzenia w nauce Pythona. To bardzo przyjemny język.
iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

To jest wskaźnik, tak samo jak w Javie. Tylko zapis jest inny.

Kopiuj
void modifyPtr(Foo* foo)
{
    foo = new Foo;
}

void modifyFoo(Foo* foo)
{
    foo->bar = baz;
}

Foo* foo = new Foo;
modifyPtr(foo); // niezmieniony
modifyFoo(foo); // zmieniony

jest równoznaczne z Javowym (i, jak widać, Pythonowym):

Kopiuj
void modifyPtr(Foo foo) {
    foo = new Foo();
}

void modifyFoo(Foo foo) {
    foo.bar = baz;
}

Foo foo = new Foo();
modifyPtr(foo); // niezmieniony
modifyFoo(foo); // zmieniony

Dla referencji nie ma odpowiednika, nie można też wyłuskać wskaźnika (więc nie można przypisać innego obiektu do danego adresu).

Kopiuj
void modify(Foo& foo)
{
    foo = Foo();
}

void modify(Foo* foo)
{
    *foo = Foo();
}

Obydwie funkcje zmieniają wartość pod adresem wskaźnika (wywołują operator przypisania), a nie samą wartość wskaźnika - co jest niemożliwe w Javie z w/w powodów.
Problemem jest to, że co innego nazywa się referencją w Javie (Pythonie), a co innego w C++. Po prostu źle dobrany termin. W każdym razie nie jest to pass by ref.
I ofc nie ma też przekazywania przez wartość obiektów.

edytowany 13x, ostatnio: iooi
0
iooi napisał(a)

To jest wskaźnik, tak samo jak w Javie. Tylko zapis jest inny.

W jednym z listingów wyżej udowodniłem że to nie jest "wskaźnik".

iooi napisał(a)

Dla referencji nie ma odpowiednika, nie można też wyłuskać wskaźnika (więc nie można przypisać innego obiektu do danego adresu).

Tak samo w Pythonie nie można przypisać nowej referencji do już istniejącej... Popatrz na listingi, które były wcześniej.

iooi napisał(a)

W każdym razie nie jest to pass by ref.
I ofc nie ma też przekazywania przez wartość obiektów.

Te dwa zdania są sprzeczne. Skoro nie jest to przekazanie przez referencję, obiektów nie można przekazać przez wartość, a w Pythonie nie ma wskaźników, to z Twojej wypowiedzi wynika, że nie ma możliwości przekazania obiektu do funkcji.

vpiotr
Ależ można przypisać - przecież to pokazałem (patrz ost. przykład w Python).
iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

Udowodniłeś, dając przykład przekazywania przez wartość. Odpowiednikiem twojego:

Kopiuj
void funA(int i)
{
    int i = 2; // chodziło pewnie o i = 2;
}

Byłoby, wykorzystując foologię:

Kopiuj
void funA(Foo foo)
{
  foo = Foo();
}

Czego ani w Javie, ani w Pythonie zrobić się nie da (w Javie np. obiektu nie da się przekazać w ogóle - zawsze będzie to wskaźnik).

Przy okazji znalazłem ciekawy materiał:
http://javadude.com/articles/passbyvalue.htm

Tutaj fragment z JLS:

The reference values (often just references) are pointers to these objects, and a special null reference, which refers to no object.

edytowany 5x, ostatnio: iooi
0
iooi napisał(a)

Udowodniłeś, dając przykład przekazywania przez wartość.

Nie. Dowód masz tutaj (powtórzę):

Kopiuj
#!/usr/bin/env python
 
def funA(somelist):
        print('List in funA() before append(): ' + str(id(somelist)))
        somelist.append(1)
        print('List in funA() after append(): ' + str(id(somelist)))
        somelist = [4, 5, 6]
        print('List in funA() after assign: ' + str(id(somelist)))
 
 
def funB():
        mylist = [2, 3]
        print('List in funB() before call: ' + str(id(mylist)))
        funA(mylist)
        print('List in funB() after call: ' + str(id(mylist)))
        print('Contents: ' + str(mylist))
 
 
funB()
iooi napisał(a)

Odpowiednikiem twojego:

Kopiuj
void funA(int i)
{
    int i = 2; // chodziło pewnie o i = 2;
}

Nie, to nie jest dowód. To było zobrazowanie tego, co miałem na mysli pisząc o przykrywaniu. I nie chodziło o i = 2, lecz dokładnie o to, co tam jest napisane.
Bardzo Cię proszę o przeczytanie uważnie całej dyskusji i dopiero po tym zabieranie głosu.

iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

Ale to żaden obraz, to tylko compile-error.
A ten dowód właśnie pokazuje, że do funkcji nie była przekazana referencja (znana z C++), tylko zwykły wskaźnik. Chyba, że nie wiesz, jak działają referencje w C++.

edytowany 1x, ostatnio: iooi
1

Panowie, wszyscy się mylicie. @iooi, proszę, nie mieszaj do tego Javy, która nie jest językiem w pełni obiektowym, w przeciwieństwie do Pythona. Mówienie o wskaźnikach nie ma tutaj najmniejszego sensu.

Kumashiro napisał(a)

Słownik jest typem złożonym. W Pythonie wszystkie zmienne typów złożonych są referencjami. Zwracanie typu złożonego, przekazanego w argumencie (jak pokazuje sposób pierwszy) nie ma większego sensu. To rozwiązanie stosuje się w przypadku typów prostych, które są kopiowane w funkcjach

Python nie posiada rozróżnienia na value types i reference types, tutaj nie ma trzymania, bądź przekazywania, przez wartość, absolutnie wszystko jest na swój sposób "referencyjne". Sytuacja jest identyczna jak w LISPie, pewne instancje są widziane pod pewnymi symbolami, nie są z nimi fizycznie związane. W Pythonie nie ma niejawnego kopiowania obiektów, ew. kopiowanie zawsze należy przeprowadzić ręcznie.

Zacznijmy od podstaw, tj. "wszystko jest obiektem" (do tego pierwszej kategorii). "Typy proste" z Javy czy C++ w Pythonie są pełnoprawnymi obiektami, chociaż nie posiadają wewnętrznej wartości, z punktu widzenia użytkownika są niezmienne. Funkcje i metody są obiektami pierwszej kategorii, możemy więc posługiwać się nimi na równi z innymi instancjami:

Kopiuj
# postać bezpośrednia
obiekt.metoda(69)
# równoważna konstrukcja wynikajaca z powyższej własności:
zrobCoś = obiekt.metoda
zróbCoś(666)

Powiedzmy, że chcemy stworzyć własne funkcje do inkrementacji, dekrementacji i negacji liczb, większość ludzi mających mylne pojęcie o Pythonie zrobi to tak (lub posługując się lambdami):

Kopiuj
def inc(x):
    return +1 + x

def dec(x):
    return -1 + x

def neg(x):
    return -1 * x

Jest to podejście wywodzące się z przeświadczenia, że licza jest wartością, tak jak w prymitywnym C++, czy nieudolnie zaprojektowanej Javie. Jak już wspomniałem, w Pythonie wszystko jest obiektem, do tego metody są obiektami pierwszej kategorii, stąd też możemy powyższe zapisać w sposób następujący:

Kopiuj
inc = (+1).__add__
dec = (-1).__add__
neg = (-1).__mul__

"Wartościami" inc, dec i neg są metody zbindowane z obiektami, na rzecz których zostaną wywołane (czy też właściwie, z których pochodzą) czyli lewą stroną operatora, dopiero czekają na argument (tj. prawą stronę operatora). Przykład może trochę naciągany, ale jego celem jest demonstracja mechaniki.

No dobrze, skoro liczby są obiektami, to dlaczego można wykonywać na argumencie funkcji operacje np. += i nie zmienić zewnętrznej zmiennej? Odpowiedź jest prosta: typy 'niezmienne' (liczby, krotki frozensety etc.) nie posiadają operatorów skróconego przypisania, tj. __iadd__ etc. Operacje skrócone realizowane są w następujący sposób: jeżeli obiekt posiada metodę realizującą skróconą operację to zostanie ona wykonana, w przeciwnym wypadku zostanie użyta operacja podstawowa w pełnym wymiarze. Jeżeli obiekt oferuje modyfikacje in-place to zostają one wykonane, chociaż to na metodzie spoczywa odpowiedzialność za zwrócenie "referencji" do obiektu, który jest wynikiem takiej operacji, także nawet modyfikacja in-place może dać na wyjściu inny obiekt, inną wartość zmiennej, chociaż nie jest to zalecane. Przykładowa sesja z IPythona potwierdzająca akapit:

Kopiuj
In [1]: hasattr(0, '__add__')
Out[1]: True

In [2]: hasattr(0, '__iadd__')
Out[2]: False

In [3]: class UdajemyInta(object):
   ...:     def __init__(self, value):
   ...:         self.value = value
   ...:     def __add__(self, other):
   ...:         return UdajemyInta(self.value + other.value)
   ...:     def __str__(self):
   ...:         return str(self.value)
   ...:     def __repr__(self):
   ...:         return repr(self.value)
   ...:

In [4]: def fun(x):
   ...:     x0 = x
   ...:     x += x
   ...:     print('Czy ten sam? %s. Wartosc: %s.' % (x0 is x, x))
   ...:

In [5]: lista = [69, 666]

In [6]: fun(lista)
Czy ten sam? True. Wartosc: [69, 666, 69, 666].

In [7]: udawanyInt = UdajemyInta(666)

In [8]: fun(udawanyInt)
Czy ten sam? False. Wartosc: 1332.

Na koniec możemy jeszcze sprawdzić wartości naszych dwóch zmiennych (lista i udawanyInt) po wyjściu z funkcji wykonującej +=:

Kopiuj
In [9]: lista
Out[9]: [69, 666, 69, 666]

In [10]: udawanyInt
Out[10]: 666

int nie posiada operatora +=, tak samo jak nasz ewidentnie "złożony" typ, mimo wszystko kod się wykonuje, co więcej wyniki dla "udawanego inta" są takie, jakie powinny być dla "typu prostego". No i co, panowie? W Pythonie WSZYSTKO jest "referencją" (chociaż wewnętrznie dokonywane są optymalizacje reprezentacji), z typów "prostych" (poza boolean i NoneType) można nawet dziedziczyć.

Cholera, zostawić Was na dwa dni to nowego Pythona wynajdziecie...

0

Racja. Moje postrzeganie było upośledzone. No cóż, człowiek uczy się całe życie :)
Ale i tak moja teoria była zabawniejsza...

msm
A ja podziwiam twoją cierpliwość w powtarzaniu tego samego. Nawet jeśli nie do końca miałeś rację.
iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

Mieszam w to Javę, bo była tu wywoływana i jest C-like, więc można było łatwiej odwołać się do (również wywołanego) C++.
To, co pokazałeś, nie jest żadnym specjalnym zachowaniem i nie wiem za bardzo, jak to się ma do naszej dyskusji. Jeśli nie Java, to odpowiednik w Scali (tak, tej Scali, która działa na JVM!), którego działanie jest identyczne:

Kopiuj
case class UdajemyInta(value: Int) {
  def +(other: UdajemyInta) = UdajemyInta(value + other.value)
  override def toString = value.toString
}

def fun(x: ListBuffer[Int]) {
  var x0 = x
  var x1 = x
  x1 ++= x  // nieznaczaca roznica
  printf("Czy ten sam? %s. Wartosc: %s.%n", x0 eq x1, x1)
}

// Scala nie jest dynamicznie typowana
def fun(x: UdajemyInta) {
  var x0 = x
  var x1 = x
  x1 += x
  printf("Czy ten sam? %s. Wartosc: %s.%n", x0 eq x1, x1)
}

val lista = ListBuffer(69, 666)
fun(lista)
// Czy ten sam? true. Wartosc: ListBuffer(69, 666, 69, 666).

val udawanyInt = UdajemyInta(666)
fun(udawanyInt)
// Czy ten sam? false. Wartosc: 1332.

Oczywiście, że mówienie o wskaźnikach nie ma tu sensu, ale tylko dlatego, że to zbyt wysoki poziom abstrakcji - jednak w każdym razie, żaden z tych języków nie posiada referencji w stylu C++.

edytowany 8x, ostatnio: iooi
0
iooi napisał(a)

Mieszam w to Javę, bo była tu wywoływana i jest C-like, więc można było łatwiej odwołać się do (również wywołanego) C++.
To, co pokazałeś, nie jest niczym specjalnym i nie wiem za bardzo, jak to się ma do naszej dyskusji. Jeśli nie Java, to odpowiednik w Scali (tak, tej Scali, która działa na JVM!), którego działanie jest identyczne

Doskonale wiem, że w Scali działa to identycznie jak w Pythonie. Jak to się ma do dyskusji? Wątek nie jest o Javie czy C/C++ tylko o Pythonie, do tego siejecie dezinformację nt. przekazywania przez wartość. Jako osoba znająca Scalę już dawno powinieneś zastrzec, że immutable nie oznacza by-value.

iooi
  • Rejestracja:ponad 14 lat
  • Ostatnio:ponad 11 lat
  • Postów:573
0

Nikt nie twierdził, że cokolwiek jest tu przekazywane przez wartość. Ja starałem się tylko sprostować, że nie jest przez referencję ("Nie. Referencja jest "etykietką". W Pythonie działa tak samo jak np. w C++ czy Javie.").

vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
0
iooi napisał(a)

Nikt nie twierdził, że cokolwiek jest tu przekazywane przez wartość. Ja starałem się tylko sprostować, że nie jest przez referencję ("Nie. Referencja jest "etykietką". W Pythonie działa tak samo jak np. w C++ czy Javie.").

Za to sobie cenię Delphi czy Jave (której zresztą poza tym nie znam), że obiekty zawsze przekazywane są w ten sam sposób - wskaźnikiem. A nie referencją, wskaźnikiem, przez wartość czy przez smart pointer...
Wbrew pozorom to minimalizowało wycieki, bo wiadomo było, że jak się jakiś obiekt tworzy to trzeba go zwolnić i kropka.

Zobacz pozostałe 2 komentarze
msm
Nie używam Delphi (kiedyś pisałem w Pascalu), kilka razy widziałem kod asemblera wygenerowany z Delphi. Ale nie powiesz mi chyba że Inty są przekazywane domyślnie wskaźnikiem? Chyba że się mylę, patrzenie na kod binarny to kiepski sposób poznawania języka.
vpiotr
Nie powiem Ci. Ale przeczytaj dokładnie to co komentujesz...
iooi
@msm: rozumiem, że trollujesz, ale nie wprowadzaj w błąd innych. W Javie nie można przekazywać obiektów W OGÓLE i jest zawsze pass by value.
msm
@vpiotr - ok, nie zauważyłem tego szczegółu... @iooi - nie piłem dzisiaj kawy, chyba nie jestem sobą. Idę stąd i nie wracam bo ten temat na mnie źle działa :(.
vpiotr
OK, dla mnie EOT bo ten temat jest już męczący
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)