Python okiem pehapowca

Mamy niedzielę. W ramach leniu­cho­wa­nia zachciało mi się poznać jakiś nowy język progra­mo­wa­nia. Padło na Pythona (nieznacz­nie wygrał z Rubym).

Na pierw­szy rzut oka to w zasa­dzie taki Java­Script ogól­nego prze­zna­cze­nia bez prze­glą­darki. Python rekla­mo­wany jest jako język typu batte­ries inclu­ded, czyli stan­dar­dowa biblio­teka powinna zawie­rać wszystko to, co w typo­wych zasto­so­wa­niach progra­mi­sta potrzebuje.

Od razu widać puryzm kodu Pythona. Żadnych klame­rek, żadnych średni­ków — wszystko zała­twiamy wcię­ciami i końcami linii. „Kompre­sja kodu” widoczna jest na każdym kroku, np. funk­cje dekla­ru­jemy poprzez def, a nie przy­dłu­gawe func­tion, obiekty tworzymy bez new. Weźmy na przy­kład najprost­szą funk­cję żądającą od użyt­kow­nika wpisa­nia z klawia­tury jakiejś liczby:

def getIntInput(message):
    while True:
        try:
            return int(input(message))
        except ValueError:
            print("You were supposed to enter integer!")

W 6 liniach mamy zała­twioną prośbę o wpisa­nie czegoś, prze­two­rze­nie wejścia i wyła­pa­nie ewen­tu­al­nych błędów. Funk­cja nie odczepi się od użyt­kow­nika dopóki nie wpisze popraw­nie jakichś cyferek.

wiek = getIntInput("Podaj rok urodzenia")

Poni­żej w punk­tach cieka­wostki, które w Pytho­nie są, a których nie ma w PHP (tyle co w ciągu kilku godzin udało mi się wyłapać):

  • wspo­mniane już braki klame­rek i średni­ków — czy naprawdę potrze­bu­jemy tego wszyst­kiego w PHP?
  • wszyst­kie metody publiczne — tego nie popie­ram, może powo­do­wać bajzel w API; zgod­nie z konwen­cją metody prywatne należy ozna­czać przed­rost­kiem _
  • fajne konstruk­cje przy itero­wa­niu: for zmienna in array oraz for zmienna in range(5)
  • dziwne zasady doku­men­to­wa­nia kodu — komen­ta­rze idą po dekla­ra­cji klasy czy metody
  • array compre­hen­sion (nawet nie wiem jak to prze­tłu­ma­czyć) — w jednej linijce możemy stwo­rzyć nową tablicę na podsta­wie starej i prze­je­chać jakąś funk­cją po każdej warto­ści przed dodaniem:
    nowaTablica = [funkcja(wartosc) for wartosc in staraTablica]
  • proste loso­wa­nie:
    zagadka = random.choice(["wartosc1","wartosc2","wartosc3"])
  • tuple, czyli nieda­jąca się mody­fi­ko­wać tablica; co ciekawe, funk­cje bardzo często zwra­cają to ustroj­stwo, możemy od razu złapać je do dwóch różnych zmiennych
    wynik1, wynik2 = funkcja()
  • obiekt None zamiast null
  • == i != do spraw­dza­nia warto­ści zmien­nych, isis not do porów­ny­wa­nia z None lub refe­ren­cji, mało tego, możliwa jest konstruk­cja 0 <= a <= 10
  • próba poró­wa­nia if „3” < 4 wywali Type­Er­ror
  • konstruk­cja final do kompletu z try/except
  • bajer dla mnie: if szuka­na­Zmienna in tablica oraz if „wyraz” in przeszukiwanyString
  • nie ma czegoś tak paskud­nego jak RESOURCE

Tyle na począ­tek. Widzę, że Python to fajna sprawa. O wszyst­kim pomy­śleli. Nawet o wbudo­wa­niu bazy danych sqlite w biblio­tekę stan­dar­dową. Jeżeli ktoś waha się czego by tu nowego się pouczyć to polecam!

P.S.: Tak, wiem, na tych waszych poli­bu­dach Pythona uczą już na I roku, ble ble srutu­tutu. Samo­ucy typu np. ja muszą sami. Dobra, kończę, bo i piwo mi się skoń­czyło :-(

Wygrzebane z GitHuba (3) : Validation

W dzisiej­szym odcinku weźmie udział „najwspa­nial­szy z kiedy­kol­wiek stwo­rzo­nych silnik do wali­da­cji danych w PHP” — Vali­da­tion. Projekt rozwija groź­nie brzmiąca grupa progra­mi­stów o nazwie Respect z Brazy­lii. Mam nadzieję, że po tym wpisie nie wylą­duję w lesie wycią­gnięty z bagaż­nika jakie­goś starego Mercedesa…

Projekt speł­nia normy, które są oczy­wi­ste przy czyta­niu kodu takich gigan­tów jak Zend Frame­work 2 czy Symfony, a więc używa­nie name­spa­ces, drze­wia­sta struk­tura klas i kata­lo­gów, kompa­ty­bil­ność ze stan­dar­do­wym auto­lo­ade­rem klas SplC­las­sLo­ader, własne rozsze­rze­nia wyjąt­ków. Jedyny zgrzyt to poziom doku­men­ta­cji. Auto­mat raczej nie da rady w pełni wyge­ne­ro­wać typów para­me­trów metod i zwra­ca­nych warto­ści. W nagrodę za to dostęp­nych jest dzie­siątki testów jednost­ko­wych. Co jak co, ale wali­da­tor spraw­dza­jący czyjeś dane sam powi­nien być grun­tow­nie spraw­dzony ;-)

Powszech­nie wiadomo, że w PHP nie można użyć konstruk­cji typu

new Obiekt()->metoda();

Zamiast tego można stoso­wać metody statyczne, które w rezul­ta­cie zwrócą nam obiekt lub też można zasto­so­wać tak lubia­nego przez was Harrego Pottera. Twórcy biblio­teki czarują często i gęsto.

Auto­rzy Vali­da­tion propo­nują używa­nie w nastę­pu­jący sposób:

// deklarujemy uzywany namespace i robimy alias do klasy Validator
use Respect\Validation\Validator as v;
 
// mozemy albo najpierw przygotowac obiekt walidatora
$walidator = v::string()->between('a', 'c');
 
// albo tez bezposrednio uzywac w instrukcjach warunkowych, np.
if (v::numeric()->positive()->validate($cos)) echo 'prawda';
 
//i potem uzywac do sprawdzania jednej z trzech metod:
 
// zwroci tylko true albo false
$walidator->validate($cos);
 
// wypluje wyjatek z pierwszym bledem
$walidator->check($cos);
 
// wypluje wyjatek ze wszystkimi bledami
$walidator->assert($cos);

Warun­ków, które możemy spraw­dzać jest kilka­dzie­siąt. Można popa­trzeć po plikach. Z ciekaw­szych to wymie­niony wyżej

between()

dla zakresu znaków,

in(array('wartosc1' , 'wartosc2))

dla dozwo­lo­nych warto­ści oraz konstrukcja

v::each(v::warunek())->validate(array('wartosc1','wartosc2'));

dla spraw­dze­nia wszyst­kich warto­ści w tablicy. Ponadto można tworzyć kompo­zyty różnych warun­ków za pomocą

v::allOf($walidator1,$walidator2);

(jeżeli wszyst­kie muszą przejść) oraz

oneOf()

(jeżeli wystar­czy nam, że przej­dzie tylko jeden z warun­ków żeby wali­da­cja była poprawna). Dodat­kowo można używać wali­da­to­rów z Zend Frame­worka i Symfony.

Tyle było chwa­le­nia, teraz wady:

  • zamie­sza­nie w wyjąt­kach — często widzimy {{failed}} zamiast komu­ni­katu błędu,
  • zachę­ca­nie do bezpo­śred­niego majstro­wa­nia przy niepu­blicz­nych polach obiek­tów za pomocą metody attri­bute() (w bebe­chach widać, że metoda zmie­nia dostęp do zmien­nej za pomocą klasy Reflec­tion­Pro­perty) zamiast tego attri­bute() powinno przyj­mo­wać ewen­tu­al­nie nazwy metod dostę­po­wych do zmien­nych i w ten sposób sprawdzać.

Tak czy siak, projek­tanci idą w dobrym kierunku. Wszystko ładnie ze sobą współ­pra­cuje, ja kilku nowych trików się nauczy­łem. Pozo­staje bacz­nie obser­wo­wać postępy. Pozdro dla pozo­sta­łych GitHu­bo­wych podglą­da­czy ;-)

Jak poprawnie uczestniczyć w rozwoju projektu na Github

Najpierw rzecz niezwią­zana z tema­tem: Używa­cie Google Plus? Dodaj­cie mnie do swoich kręgów. Jak ktoś nie ma zapro­sze­nia to napi­sać maila — podeślę.

Od kilku dobrych miesięcy GitHub jest moim ulubio­nym serwi­sem z dzie­dziny progra­mo­wa­nia. Najlep­sze w nim jest to, że możemy za całko­witą darmo­chę tworzyć nowe projekty Open Source i obser­wo­wać rozwój istnie­ją­cych. A co, jeżeli chcemy dorzu­cić do kodu coś od siebie? Wtedy musimy prze­strze­gać pewnych proce­dur, o których dzisiaj będzie wpis.

Zanim jednak to nastąpi, musimy nauczyć się obsługi Gita, czyli systemu kontroli wersji, który obowią­zuje na GitHu­bie. Przy­znam, że trzeba się trochę pomę­czyć z konsolą żeby to ustroj­stwo zaczęło nas słuchać. Jest oczy­wi­ście kilka nadbu­dó­wek graficz­nych, jednak aby dobrze poznać Gita, trzeba używać konsoli (analo­gicz­nie do stuka­nia HTMLCSS w notat­niku, bez żadnych podpo­wia­da­czek). Nie będę w tym miej­scu zasu­wał wam porad­nika obsługi Gita, zamiast tego skie­ruję do książki Pro Git o Gicie, rozwi­ja­nej… w Gicie :-D Pierw­sze trzy rozdziały są ładnie prze­tłu­ma­czone na polski, ja trochę tłuma­czę kawałki czwartego.

Zakła­dam, że macie zało­żone konto na GitHub.com. Zakła­dam również, że na swojej lokal­nej maszy­nie macie zain­sta­lo­wa­nego Gita. W Ubuntu proces składa się z wpisa­nia w terminalu

sudo apt-get install git-core

na Window­sie nie wiem, nie znam się, nie chcę wiedzieć, nie używam ;-)

Do rzeczy:
1. Znaj­du­jąc się w projek­cie, który chcemy wspo­móc, klikamy przy­cisk Fork, co utwo­rzy naszą osobi­stą wersję projektu, nad którą mamy całko­witą władzę.

2. Tworzymy na naszym kompu­te­rze jakiś kata­log, w którym trzy­mana będzie kopia projektu. Następ­nie inicju­jemy Gita i klonu­jemy naszego forka na lokalną maszynę.

git init
git clone https://nasz_login@github.com/nasz_login/forkowany_projekt.git

3. Przy­jęło się, że repo­zy­to­rium, z którego forku­jemy nazywa się upstream, a nasz fork nazywa się origin. Repo­zy­to­rium origin tworzy się auto­ma­tycz­nie przy klono­wa­niu. Upstream musimy sobie stwo­rzyć sami.

git remote add upstream https://github.com/projekt_glowny/projekt_glowny.git

4. Tworzymy sobie gałąź zwią­zaną z proble­mem, którym chcemy się zająć (np. tłuma­cze­niem, zgło­szo­nym bugiem itp.) i prze­cho­dzimy do niej (w moim przy­padku polish-translation). Nigdy nie wpro­wa­dzamy zmian w kodzie gałęzi master!

git branch polish-translation
git checkout polish-translation

W tym momen­cie możemy dziel­nie walczyć z kodem. Pamię­tamy jednak, że inni w tym samym czasie również pracują nad projek­tem i wpro­wa­dzają zmiany. Musimy co jakiś czas zsyn­chro­ni­zo­wać się z tym co wytwo­rzyli. Proce­dura składa się z kilku czyn­no­ści:
– pobra­nie aktu­al­nej wersji repo­zy­to­rium upstream
– przej­ście do naszej głęzi master i synchro­ni­za­cja jej z upstream
– synchro­ni­za­cja naszej gałęzi robo­czej z naszym masterem

git fetch upstream
git checkout master
git rebase upstream/master
git checkout polish-translation
git rebase master

Do synchro­ni­za­cji zawsze używamy pole­ce­nia rebase, nigdy merge! Rebase opisany w podręcz­niku.

5. Zbijamy nasze cząst­kowe zatwier­dze­nia zmian (brzydko zwane commi­tami) w jeden. Osoba, która będzie włączała naszą gałąź do głów­nego projektu nie będzie miała raczej ochoty wrzu­cać 10-ciu naszych commi­tów w stylu WTF it isn’t working?, fancy addi­tion here, maybe this one will work itp. Wystar­czy poje­dyn­cze Fixed issue #5.
Począt­ku­ją­cym może spra­wić nieco trud­no­ści, dlatego krok po kroku wytłu­ma­czę:
Powiedzmy, że nasze tłuma­cze­nie składa się z 5 commi­tów. Jeżeli nie wiemy to używamy pole­ce­nia git log. Musimy cofnąć się o te 5 zmian i skleić je w jedną. Wpisu­jemy w terminalu

git rebase -i HEAD~5

W edyto­rze pick zosta­wiamy tylko w pierw­szym naszym commi­cie. Resztę zamie­niamy na squash. Zapi­su­jemy zmiany poprzez Ctrl+O, Enter i Ctrl+X. Następ­nie w pierw­szej linijce wpisu­jemy ładny komu­ni­kat, a resztę lini­jek możemy poprze­dzić haszem # Znowu Ctr+O, Enter, Ctrl + X. Spraw­dzamy czy komu­ni­kat jest taki jak trzeba poprzez git log. Jeżeli nie, zawsze możemy użyć

git commit --amend

i popra­wić treść ostat­niego commita.

6. Na wszelki wypa­dek wyko­nu­jemy ponow­nie proce­durę synchro­ni­za­cji z upstream. Jeżeli wszystko poszło dobrze, jeste­śmy gotowi do prze­sła­nia naszych zmian na serwer origin (nasz fork na GitHubie).

git push origin polish-translation

7. Wcho­dzimy na stronę ze swoim forkiem i spraw­dzamy czy w sekcji Switch Bran­ches poja­wiła się nasza gałąź. Jeżeli tak to klikamy na pull requ­est, wybie­ramy naszą gałąź i zatwier­dzamy prośbę o połą­cze­nie z gałę­zią master forko­wa­nego projektu.
Teraz pozo­staje tylko cier­pli­wie czekać i mieć nadzieję, że auto­rom się spodoba i zatwier­dzą zmiany. Jeżeli nie, w sekcji pull requ­ests głów­nego projektu na pewno dosta­niemy komu­ni­kat co jest nie tak.