on the verge of extinction... again

python, dupa primii pasi

dizzy python

Imaginea este de fapt facuta din trei imagini. Animalu' este de fapt logo-ul wxPython, luat de pe vanille-media.de, caramida este o bucata dintr-o imagine gasita pe clipartof.com, iar stelutele sunt bucati dintr-un .psd de pe officialpsds.com. Toate redimensionate aiuristic si trantite la gramada intr-un jegulet de editor. Plus ceva explicatii.

Care au fost foarte putini pana la momentul de fata, pentru ca am inceput de-abia de trei zile, care au fost de fapt dupa-amieze in care nu m-am concentrat in primul rand pe limbaj in sine, ci pe ceea ce ar trebui sa fac cu el1. Sa speram ca n-o sa se transforme in alte chestii pe care le las balta.

Cu ocazia asta, m-am jucat ceva mai mult intr-un... loc de joaca online. Loc de joaca ce poate fi gasit la adresa ideone.com. Se alege limbajul din partea stanga (de la "choose language"), "syntax highlight" ajuta mereu si de-aia e bine sa fie bifata (se gaseste in dreapta, sub source box). Si pentru Python in particular mai trebuie bifata doar casuta de "run code". Apoi se tranteste codul in source box si la final se da click pe "submit".

Cine vrea poate sa isi faca si cont, insa nu este obligatoriu. Link-urile cu codul sursa si rezultatele (vizibile in partea de jos, in caseta de sub "output") sunt oricum disponibile in mod public. Desigur, codul nu poate fi editat fara logare, asa ca solutia mea pentru editarea propriului cod fara logare este... butonul de "Back" al browserului. Si altfel, copy-paste la cod. Bineinteles ca in cazurile astea nu poate fi vorba de o editare propriu-zisa, iar link-ul nu ramane acelasi.

Prima chestie care nu mi-a placut2 la Python este ca nu stie sa-mi faca automat conversie de tip sau cum dracu' i-o fi zicand in romana. In orice caz, ma refer la faptul ca dracia de mai jos nu merge (live link):

print "got a " + 7
# >>> TypeError: cannot concatenate 'str' and 'int' objects

Desigur, se poate face asa ceva (live link):

print "got a " + str(7)
# >>> got a 7

... sau, oarecum asemanator cu C (live link):

print("got a %s" % 7)
# >>> got a 7

... si viata este din nou frumoasa multumita Sfantului Google3. Adica fara erori. De-a dreptul amuzant este insa ca merge asa ceva (live link):

print "got a " * 7
# >>> got a got a got a got a got a got a got a 

Exact, repeta sirul de caractere de 7 ori.

Ce mi-a placut a fost faptul ca pot extrage usor bucati dintr-un sir de caractere (live link).

str = 'the little dinosaur'
# format: string_name[start_pos_incl:stop_pos_excl]
# zero-based index
# the little...
# 0123456789...
print str[4:]
# >>> little dinosaur
print str[4:10]
# >>> little
# negative index: 
# count from the end of str, with -1 being the last position
print str[:-4]
# >>> the little dino
print str[-4:]
# >>> saur

Mi s-a parut ciudat ca nu exista o delimitare clara a blocurilor de cod. In C/ C++, Java, JavaScript, PHP (as zice chiar si CSS, desi e o alta culoare de drac) am acolade intre care sa pun bucatile alea de cod. In VisualBasic am End (End Sub, End If). In cazul Python, trebuie sa ma bazez doar pe spatii, pe indentare4. Ma rog, e clar ca o functie nu poate merge mai departe de return, dar totusi... in exemplul stupizel de mai jos, indentarea face totul (live link):

t = ''
def g(a):
    if len(a) > 2:
        t = a
        print t + " if"
    else:
        t = ''
        print t + " else"
g('test')

Ah, si mi s-a intamplat de atatea ori sa uit cele doua puncte de dupa un for sau if.

Mi s-a parut ciudat ca trebuie sa folosesc si ?: dupa paranteza de deschidere ( atunci cand vreau sa grupez parti ale unei expresii regulate. Prima data am incercat fara si m-am tot dat cu capul de pereti ca nu mergea, asa ca am rescris totul altfel. Dupa mai putin de un sfert de ora descopeream cum ar fi trebuit sa procedez de la inceput. Draci, scroll inapoi in sus, rescris bucata. In orice caz, un mic exemplu5 (live link):

# really, dino needs an import here
import re
regex = r"[a-z]+(?:\-[a-z]+)?"
# should match
test1 = "dino"
test2 = "dino-saur"
print re.findall(regex, test1) == [test1]
#>>> True
print re.findall(regex, test2) == [test2]
#>>> True
# should not match:
test1 = "di-no-saur"
test2 = "dino--saur"
print re.findall(regex, test1) == [test1]
#>>> False
print re.findall(regex, test2) == [test2]
#>>> False

In Python am o chestie numita dictionary, care seamana cu un JSON.

Si cam asta e cu Python (daca n-am uitat de vreun alt maruntis care mi-a placut sau m-a enervat in zilele astea trei). Pana acum.

  • 1 Cu alte cuvinte, m-am apucat sa scriu cod Python asa cum m-am apucat sa scriu CSS: fara sa mai fi trecut macar o singura data prin vreun curs, fara sa am nici cea mai mica idee ce dracu' fac, bazandu-ma pe o cautare rapida si documentare in momentele de "oare cum dracu' o fi sintaxa pentru asa ceva?".
  • 2 Deh, obisnuinta JavaScript, la fel ma plangeam in ianuarie, cand m-am reapucat de PHP, de lipsa a asa ceva: f(a)[i]. Edit: live and learn... nu este o idee buna sa fac asta nici in JavaScript.
  • 3 Cred ca pot sa-i spun "la multi ani!" ca parca mama zicea ca azi e Sfantu' Gheorghe si parca pare putin derivat de acolo.
  • 4 M-a enervat la culme cand am primit erori legate de indentare.
  • 5 Documentatie findall (vine de la "find all").

6 pareri

cine
Cristi
cand
luni, 23 aprilie 2012 la 20:08:00 EEST
Eu cred ca f(a)[i] n-ar trebui sa existe nici in JavaScript. Functia se apeleaza pentru fiecare i, deci este extrem de ineficient.
Dar... De ce Python? Mai ales ca stii deja PHP...
cine
brontozaurel
cand
luni, 23 aprilie 2012 la 21:11:00 EEST
OK, probabil n-ar fi trebuit sa folosesc i, pentru ca, desi am scris i avand index in minte, nu m-am gandit in primul rand la o bucla cu f apelat pentru fiecare i, ci la a apela un anumit index al unui array intors de f. Sau mai generic, la a accesa o anumita proprietate cu un nume cunoscut (si anume stringul i, care poate fi de exemplu "dino" sau ce dracu' vrea el) a unui obiect pe care il intoarce functia f (si a ala este si el generic, poate sa nu fie nimic acolo sau pot fi 27 de argumente... desi de obicei are argumente si nu tin sa fi ajuns vreodata la 27... si jumatate mi se par multe).

Personal, mi s-a parut o chestie utila sa pot scrie
v = f(a)[i]
in timp ce in PHP nu pot scrie asa direct, trebuie sa am ceva de genul
obj = f(a)
v = obj[i]

Python... pentru ca asta folosesc cursurile Udacity (m-am apucat de 3 din cele care au inceput acum o saptamana). Problemele care apar dupa unele segmente ale cursurilor sunt in Python (they actually provide something like ideone.com for those exercises, but Python-only, so I can't write somrthing that serves the same purpose in Java for example) pentru ca Python este folosit in diverse proiecte ale celor care tin cursurile si pentru ca Python este limbajul folosit intr-un curs introductiv de programare pe care l-au oferit in iarna. Curs pe care eu nu l-am urmat, deci acum m-am cam aruncat cu capul inainte, fara sa citesc ceva manual de Python inainte, ca poate merge asa sa prind pe drum, ca la urma urmelor, baza este aceeasi, indiferent de limbaj.

Ceea ce inseamna ca eu problemele le-am rezolvat cumva gandindu-ma "OK, in Java/ C/ whatever as face chestia asta asa - cum trebuie sa o scriu ca sa mearga in Python?". Pur si simplu am cautat pe Google chestii de genu' "function append item to list Python" ca eram paralela cu limbajul. Ma rog, ofereau unele exemple din care mi-a fost destul de usor sa inteleg multe chestii - ai vazut un limbaj de programare, le-ai cam vazut pe toate...

Pana acum a mers in sensul ca m-am descurcat suficient incat sa fac (100% corect si intelegand ce dracu' fac pe acolo) toate exercitiile de pe langa cursurile video si toate temele din prima saptamana. Nu fara multi draci si mult timp consumat (mi-a luat opt ore sa ma prind ce gresesc) pentru ultima problema din tema de la cursul care intamplator mi-a placut cel mai mult pana acum, CS262 - Programming Languages - Building a Browser... stuff with regex, (non)deterministic automata & all that.
cine
Cristi
cand
luni, 23 aprilie 2012 la 22:57:00 EEST
Nu ma refer neaparat la o bucla, ci la cazul in care vrei sa folosesti mai mult de 1 element din array-ul respectiv. Aici am facut o presupunere, e adevarat, dar de obicei, daca ai scris o functie care iti intoarce mai multe valori inseamna ca vrei sa le folosesti.
Daca scrii
v = f(a)[i]
w = f(a)[j]
atunci f(a) va fi evaluat de 2 ori, iar in varianta
obj = f(a)
v = obj[i]
w = obj[j]
se evalueaza doar 1 data.
Un alt motiv pentru care nu imi place constructia respectiva este ca incurajeaza scrierea codului fara verificari pentru null. Daca codul este relativ simplu, nu e o problema, dar daca e ceva mai complicat si nici nu e scris de tine, poate sa insemne multe ore pierdute cu debug (i just hate JavaScript debugging!)

Chiar daca citeai manualul inainte, oricum erau multe ore pierdute cu cititul si cu exemplele. E mai rapid asa, chiar daca la inceput iti ia ceva mai mult timp. Sunt convins ca data viitoare o vei rezolva mult mai repede.
Problema care ti-a luat 8 ore... A fost o problema de limbaj sau de algoritm? Oricum, daca ai zis ca e un site, banuiesc ca nu are un debugger si e mult mai dificil sa identifici eroarea.
cine
brontozaurel
cand
marți, 24 aprilie 2012 la 00:20:00 EEST
Ouchie! Cumva nu m-am gandit niciodata la asta si eu is aia care pune dimensiunea unui array intr-o variabila inainte de buclele for & alte chestii de gen.
Foarte adevarat. Bagat la bibilica :)

Acum incep sa ma gandesc si la alte chestii pe care mi le-am permis. De genul obj[expr?f(a):g(b)]

Problema in sine s-a vrut a fi de algoritm (se dadeau patru exemple de automate nondeterministe ca si test cases si se cerea o functie care sa determine daca un automat generic accepta cel putin un string, oricare ar fi fost el). Ca eu am avut mici probleme si cu limbajul (googled "python ternary operator", "python get object type" & altele de gen) si cu faptul ca am sters o linie si am uitat sa inlocuiesc variabila e alta chestie.

Aveam o functie n(curr_state, ...) si undeva in interiorul ei o apelam recursiv cu un curr_state in care pusesem inainte valoarea unui next_state. Am sters linia pe care aveam curr_state = next_state, insa n-am inlocuit curr_state cu next_state in apelul functiei ca sa am n(next_state, ...). Iar dupa aia ma uitam crucis de ce s-a busit si mai tare.

Am avut probleme si cu felul in care am gandit algoritmul initial, pentru ca pusesem initial un return None pe o ramura a unui if unde ar fi trebuit de fapt sa-i spun sa continue cu urmatoarea iteratie a buclei in care era if-ul si stateam si ma minunam la output de ce dracu' se termina executia asa repede si nu-mi face verificarile si pentru celelalte stari ale automatului.

Si nu, nu am avut debugger la dispozitie, dar oricum... eu sunt putin cam... de fapt de-a dreptul toanta cand vine vorba de folosit un debugger si tot metoda cu afisat chestii in consola in diferite puncte o folosesc :-??

Ma rog, pana la urma m-am prins rand pe rand de toate si foarte probabil ca o sa casc ochii la chestii de gen pe viitor...
cine
Anonim
cand
sâmbătă, 28 aprilie 2012 la 20:48:00 EEST
Mai bine folosesti un IDE gen pydev (http://pydev.org/), iti ofera diverse functionalitati utile (code-completion, debugging, etc). In privinta faptului ca, in primul exemplu, 7 nu e convertit automat la un string, acesta e un lucru bun. Desi ar parea o functionalitate draguta (anumite limbaje permitand asta), codul ar fi mai predispus la erori.
cine
brontozaurel
cand
sâmbătă, 28 aprilie 2012 la 21:12:00 EEST
Adevarat, exista un motiv al dracului de bun pentru care unele limbaje nu permit conversia automata. Dar lenea si nerabdarea nu vor sa auda de asta.

Am un IDE instalat. Doar ca mai mult ma zapaceste. Vreau doar un spatiu in care sa scriu cod, un buton de Run si un spatiu in care sa vad rezultatul. Oricum mai mult de atat sunt incapabila sa pricep.

Da-ti si tu cu parerea!

Mai jos se pot scrie tampenii. Nu mai mari ca alea de mai sus...
Insa inainte de orice altceva, vezi cum se comenteaza: indrumar tehnic si reguli!
HTML acceptat: <b>, <i>, <a href=""> (fara alte atribute)