Názory k článku
Perličky: úvod do referencí
Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknove článku nikdo nikoho nenutil se něco učit. Tento jazyk byl vymyslen člověkem z praxe pro lidi, řešící praktické věci. V žádném případě není výlupek ctností a akademické krásy - na druhou stranu, zatím co v jiných jazycích dokončujete ještě deklarace, tak perlista už balí. Používám několik jazyků, ale díky organizované strávě modulů (CPAN) a díky časovému stresu jsem si za hlavní (a poslední) jazyk zvolil perl. A udělal jsem dobře.
Re: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknoRe: Reknete Pythonu ne
celé vláknoRe: Reknete Pythonu ne
celé vláknoGrafická úprava součástí programu
celé vláknodef merge(a, b):
ret = []
ia = ib = 0
while 1:
if ia == len(a):
if ib == len(b): break
ret.append(b[ib]); ib += 1
elif ib == len(b) or a[ia] < b[ib]:
ret.append(a[ia]); ia += 1
else:
ret.append(b[ib]); ib += 1
return ret
sub merge {
my ($a, $b) = @_;
my $ret = [];
my $ia = 0;
my $ib = 0;
while (1) {
if ($ia == @$a) {
last if $ib == @$b;
push @$ret, $$a[$ia++];
elsif ($ib == @$b or $$a[$ia] < $$b[$ib]) {
push @$ret, $$a[$ia++];
} else {
push @$ret, $$b[$ib++];
}
}
return $ret;
}
Re: Grafická úprava součástí programu
celé vláknoJo, nemuzete pastnout kod do HTML komentaroveho systemu, nemuzete psat one-linery, atd.
Pred elsif Vam chybi zavorka.
Misto $$a[$ia++] je myslim citelnejsi psat $a->[$ia++].
Hmm, jak vlastne v Pythonu reknu ze mam lokalni promennou? Pri prvnim prirazeni? To je fakt spatne, protoze pak neodhalite preklep ve jmene promenne uz v compile-time.
Michani objektoveho zapisu s funkcemi (ret.append() versus len(a)) je taky dost divne.
-Yenya
Re: Grafická úprava součástí programu
celé vláknoSouhlasim s kritikou. Navic ta dvojita reference (push @$ret, ...) je zbytecna - staci push @ret... a pak return [ @ret ];
To je argumentace stylem : umim Perl jen trochu - jednoduchy problem v nem vyresim neprehledne - takze Perl je spatny. Ja osobne bych to resil takhle - myslim ze to je jeste lepsi nez ten ukazkovy Python.
sub merge
{
my @a=@{$_[0]};
my @b=@{$_[1]};
my @ret=();
my $minlen = (@a<@b ? @a : @b);
push @ret, map { shift @a, shift @b } (0 .. $minlen-1);
push @ret, @a;
push @ret, @b;
return [ @ret ];
}
Re: Grafická úprava součástí programu
celé vláknoNicmene mi mergesort neprijde jako prilis stastny priklad, jelikoz jedna z velkych vyhod mergesortu je, ze umi radit seznamy daleko vetsi nez je dostupna pamet. Tudiz bych v tomto algoritmu neoperoval vubec s poli, ale spise bych sekvencne nacital vstupy (maximalne bych pouzil tieovane pole, ktere umi jen operace push a shift). (Pokud chci radit neco co se vejde do pameti, muzu pouzit rovnou vestavenou funkci sort.)
Jinak souhlasim s tim, ze uvedeny priklad vyse byl na primitivni urovni a navic prasacky napsan. Hodne lidi pouziva Perl jako nejake "C na steroidech". (A nejen Perl ale i PHP a dalsi jazyky s C-like syntaxi.) I temto je urcen tento serial.
Re: Grafická úprava součástí programu
celé vlákno
def merge(a,b):
for aa in a:
for bb in b:
if bb>=aa: break
yield bb
yield aa
for aa in a:
if aa>bb: break
yield aa
yield bb
for bb in b:
yield bb
a=iter([3,5,7,9,11,13,15])
b=iter([1,2,4,6,12,14,16,17])
c=merge(a,b)
print list(c)
Nejen ze funguje na jakekoli iteratory, tedy i treba radky ve 2 souborech, ale bude patrne i rychlejsi.
Re: Grafická úprava součástí programu
celé vláknoTyhle čachry s iterátorama mi teda nepřijdou moc srozumitelný. Nepřijde mi kupříkladu příliš intuitivní, jakým způsobem se tady střídá řízení mezi těmi výběry. Musel jsem nad tím chvíli přemýšlet, abych to přečetl. Inu, Python. :-)
A co takhle pěkně čistě deklarativně, pánové? ;-)
(define (merge . lists)
(match lists
((xs ()) xs)
((() xs) xs)
(((x . xs) (y . ys)) (if (< x y)
(cons x (merge xs (cons y ys)))
(cons y (merge (cons x xs) ys))))))
Re: Grafická úprava součástí programu
celé vlákno1. Že jsou komentářové systémy špatně napsané, není chyba Pythonu. Není však nic jednoduššího, než na začátek každého řádku napsat třeba tečku a pak ji odstranit v editoru pomocí označení sloupcového bloku.
Na Rootu to lze udělat pomocí html tagu:
def hello():
print "hello"
Takže v tomto případě je chybou autora, že nepoužil náhled a situaci nějak nevyřešil.
2. V Pythonu jsou všechny modifikované proměnné lokální, pokud nepoužijeme klíčové slovo global. Ochránit kód před překlepy není vždy možné a to bez ohledu na použitý programovací jazyk. Rozumný pythonista ale používá nástroje pylint nebo pychecker, které potenciálních problémů najdou opravdu hodně.
3. One-linery psát lze, ikdyž je to samozřejmě samozřejmě obtížnější než v některých jiných jazycích. Zde je moje one-line (z ohledů ke čtenářům rozdělená do více řádků, ale funguje i po spojení do jednoho řádku) verze programu beer bottles:
print (lambda beers : (globals().setdefault('beers', beers) and beers(99)))(lambda count:(((count == 0) and
("No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.")) or
((count == 1) and
("1 bottle of beer on the wall, 1 bottle of beer.\nTake one down and pass it around, no more bottles of beer on the wall.\n\n" + beers(count - 1))) or
(("%d bottles of beer on the wall, %d bottles of beer.\nTake one down and pass it around, %d bottle of beer on the wall.\n\n" % (count, count, count - 1)) + beers(count - 1))
))
Re: Grafická úprava součástí programu
celé vláknoNevidím ale stejně moc důvodů one-linery používat. Pokud chci použít Python k rychlému jednorázovému řešení nějaké situace, tak buďto použiju interaktivní prostředí Pythonu (nejlépe ipython) - Perl pokud vím tuto možnost ani nemá - a tam není důvod omezovat se jednou řádkou nebo pro opakované použití napíšu skript a tam můžu mít řádek rovněž kolik chci.
Re: Grafická úprava součástí programu
celé vláknonutnost explicitních dereferencí je něco, co by se v moderním jazyku už dávno vyskytovat nemělo.
S tim nesouhlasim. Pokud to syntakticky neodlisite, musite zaridit, aby se kazda reference chovala jako samotny objekt. To znamena, ze pri kopii reference budete kopirovat i objekt. V opacnem pripade programator nebude vedet, co se stane, kdyz napise a<-b. Respektive to bude muset nejak "odtusit" z kontextu, coz rozhodne neprispiva k vytvoreni korektniho kodu.
Číst Perl je díky těm operátorovým zvratkám vo držku
Reference v Perlu jsou jako Perl samotny. Kdo tomu nerozumi, mysli si ze to je o drzku a dela si z toho vtipy. Kdo tomu rozumi, tak uz nechce jinak :-)
Navic jako v kazdem jazyce, i v Perlu lze psat uhledny kod i bordel. Na druhou stranu, sebelepe formatovany kod nepomuze, pokud nekdo nezna syntaxi jazyka.
a to by se v perlu navíc správně mělo místo "@$a" psát "scalar(@{$a})" atp..
Nemelo, @$a je naprosto spravny zapis. Navic scalar(@{$a}) dela neco jineho.
Re: Grafická úprava součástí programu
celé vláknoNečitelnost není vlastností jazyka ale programátora. Co třeba takhle?
sub merge {
my $r_a=shift;
my $r_b=shift;
my @ret=();
my ($ia,$ib)=(0,0);
my ($ctia,$ctib)=(1,1); # 0..necti 1..cti 2..konec
my ($maxa,$maxb); # maximalni indexy
my $prveka;
my $prvekb;
$maxa=$#{@{$r_a}};
$maxb=$#{@{$r_b}};
while (1) {
$ctia=2 if ($ia>$maxa);
$ctib=2 if ($ib>$maxb);
last if ($ctia==2 and $ctib==2);
if ($ctia==1) {
$prveka=$r_a->[$ia++];
$ctia=0;
}
if ($ctib==1) {
$prvekb=$r_b->[$ib++];
$ctib=0;
}
if ($prveka<$prvekb) {
push(@ret,$prveka);
$ctia=1;
}
elsif ($prveka==$prvekb) {
push(@ret,$prveka);
push(@ret,$prvekb);
$ctia=$ctib=1;
}
else {
push(@ret,$prvekb);
$ctib=1;
}
}
return (\@ret);
Re: Grafická úprava součástí programu
celé vláknoRe: Grafická úprava součástí programu
celé vláknoSíla? Vážně? A kromě toho, že se to vám nováčkům pěkně čte to má jaké unikátní výhody? Zatím jsem si totiž všiml jediné věci: když se kód rozformátuje, tak jste v hajzlu a opravit to znamená projít a zkontrolovat celou funkcionalitu, protože pouhé odsazení má syntaktický význam - náležitost do sub-bloků kódu. Kromě toho to taky znamená, že si s tím moc nepohrajete, co? Jak to není pod sebou, je to blbě... Zajímavá myšlenka, opravdu!
Co mě ale nejvíc fascinuje - když nějaký beginner (soudím podle tvé implementace) porovnává dva jazyky a přitom zná jen jeden z nich. Fakt přínos.
Teď ti ukážu čtyři možnosti implementace: tvoji, a la Perl, lepší a správnou. První tři jsou ekvivalentní, čtvrtá funguje jak bych si představoval (obecněji). Je to subjektivní hodnocení, takže necháme ostatní, aby to posoudili. Samozřejmě existuje nekonečně mnoho způsobů jak v Perlu správně napsat to, oč jsi se pokusil ty, a to je důvod, proč mám Perl rád.
Mimochodem, nikdy nemám problém s "čitelností", kde se tahle kravina vzala? A reference? Kde bysme byli s C bez pointerů (i.e. referencí) nebo hůř, kdyby C (de)referenci provádělo automaticky?
Přiložený zdroják je samostatný, stačí paste a spustit. Je to i s benchmarkem všech metod.
#!/usr/bin/env perl
# vi:ft=perl
use Benchmark qw( :all );
my @TA1 = qw/ 1 2 3 /; # Test case A
my @TA2 = qw/ 1 5 3 4 5 6/;
my @TB1 = qw/ 2 2 3 4 5 6/; # Test case B
my @TB2 = qw/ 1 3 3 4 7 /;
my (@M1, @M2); # Vysledky
#########################[ Reseni 1 ]########################
#
# Tvoje sragora, mimochodem v prvnim "push" jsi mel chybu,
# cpal jsi do vysledku prvky pole A misto pole B. A chybela
# ti zavorka pred elsif.
#
# Uz jen ty reference a dereference vsude, pane boze!!
#
sub merge {
my ($a, $b) = @_;
my $ret = [];
my $ia = 0;
my $ib = 0;
while (1) {
if ($ia == @$a) {
last if $ib == @$b;
push @$ret, $$b[$ib++];
} elsif ($ib == @$b or $$a[$ia] < $$b[$ib]) {
push @$ret, $$a[$ia++];
} else {
push @$ret, $$b[$ib++];
}
}
return $ret;
}
@M1 = @{merge(\@TA1, \@TA2)};
@M2 = @{merge(\@TB1, \@TB2)};
print "Reseni 1a: @M1\tReseni 1b: @M2\n";
#########################[ Reseni 2 ]########################
#
# Takhle bych to napsal od boku.
# Lepsi? Co myslis?
#
sub merge2( \@\@ ) {
my @a = @{$_[0]};
my @b = @{$_[1]};
my @c = map { my @c; push @c, shift @b while $b[0]<=$_ && @b; @c, $_ } @a;
return @c, @b;
}
@M1 = merge2 @TA1, @TA2;
@M2 = merge2 @TB1, @TB2;
print "Reseni 2a: @M1\tReseni 2b: @M2\n";
#########################[ Reseni 3 ]########################
#
# To same, jen bez kopirovani poli a s primou indexaci.
#
sub merge3( \@\@ ) {
my ($a, $b) = @_;
my (@c, $i);
map { push @c, $b->[$i++] while $b->[$i] <= $_; push @c, $_ } @{$a};
return @c, @{$b}[$i..$#{$b}];
}
@M1 = merge3 @TA1, @TA2;
@M2 = merge3 @TB1, @TB2;
print "Reseni 3a: @M1\tReseni 3b: @M2\n";
#########################[ Reseni 4 ]########################
#
# Tvuj priklad ale testovaci pole spojuje blbe, viz vystup,
# protoze predpoklada, ze jsou obe setridena. Co z toho leze
# kdyz nejsou jsi videl. Ale beru, zes to tak treba chtel.
#
# Tohle reseni je ze vsech nejlepsi, protoze pole zmerguje
# i v pripade, ze nejsou predem setridena a hlavne je trikat
# rychlejsi nez ostatni (a nepotrebuje extra funkci:)
#
@M1 = sort @TA1, @TA2;
@M2 = sort @TB1, @TB2;
print "Reseni 4a: @M1\tReseni 4b: @M2\n\n";
##########################[ Timing ]#########################
my $c = 100000;
print "Cas reseni 1:\n\t"; timethis($c,
sub { @M1 = @{merge(\@TA1, \@TA2)}; @M2 = @{merge(\@TB1, \@TB2)} });
print "Cas reseni 2:\n\t"; timethis($c,
sub { @M1 = merge2 @TA1, @TA2; @M2 = merge2 @TB1, @TB2 });
print "Cas reseni 3:\n\t"; timethis($c,
sub { @M1 = merge3 @TA1, @TA2; @M2 = merge3 @TB1, @TB2 });
print "Cas reseni 4:\n\t"; timethis($c,
sub { @M1 = sort @TA1, @TA2; @M2 = sort @TB1, @TB2 });
Výstup:
Reseni 1a: 1 1 2 3 5 3 4 5 6 Reseni 1b: 1 2 2 3 3 3 4 4 5 6 7 Reseni 2a: 1 1 2 3 5 3 4 5 6 Reseni 2b: 1 2 2 3 3 3 4 4 5 6 7 Reseni 3a: 1 1 2 3 5 3 4 5 6 Reseni 3b: 1 2 2 3 3 3 4 4 5 6 7 Reseni 4a: 1 1 2 3 3 4 5 5 6 Reseni 4b: 1 2 2 3 3 3 4 4 5 6 7 Cas reseni 1: timethis 100000: 3 wallclock secs ( 2.93 usr + 0.00 sys = 2.93 CPU) @ 34129.69/s (n=100000) Cas reseni 2: timethis 100000: 3 wallclock secs ( 3.05 usr + 0.00 sys = 3.05 CPU) @ 32786.07/s (n=100000) Cas reseni 3: timethis 100000: 3 wallclock secs ( 2.75 usr + 0.00 sys = 2.75 CPU) @ 36363.64/s (n=100000) Cas reseni 4: timethis 100000: 1 wallclock secs ( 0.97 usr + 0.00 sys = 0.97 CPU) @ 103092.78/s (n=100000)
Re: Grafická úprava součástí programu
celé vláknoKod je zda se dobry, ale nektere konstrukty bych nepouzil.
V prvni verzi kodu bych asi spis nadeklaroval pole @ret a na konci udelal
"return \@ret;" - uvnitr kodu by bylo mene dereferencovani a byl by tak jeste
o kousek citelnejsi a mozna i rychlejsi.
Vsem kdo v Perlu pisou delsi veci doporuji knihu Perl Best Practices: http://www.oreilly.com/catalog/perlbp/ - ne ze bych se vsim tam uvedenym souhlasil pro sve projekty, ale aspon se autor obtezuje vysvetlit, proc si mysli ze by soucasti programatorskeho stylu neco konkretniho melo nebo nemelo byt. Je to pekne psane a prinuti to cloveka se zamyslet.
Z konstrukci ktere PerlBP nedoporucuje bych tady konkretne nepouzil prototypy v merge2 a merge3 - prototypy maji nekolik podstatnych nevyhod: napriklad chovaji se jinak v kodu ktery je uvedeny drive nez ta funkce a jinak v kodu pod ni; dale pokud uz reference na ta dve pole mate nekde z drivejska v promenne, tak nemuzete zavolat merge3(@moje_dva_arrayrefy).
Ale jinak samozrejme, TIMTOWTDI.
-Yenya
Re: Grafická úprava součástí programu
celé vlákno-Yenya
Re: Reknete Pythonu ne
celé vláknoKdyz je clanek o referencich, historku ze zivota: Znal jsem cloveka, co byl zaryty Perlista, a na Python take velmi nadaval. Shodou okolnosti nechapal, proc Python reference nepotrebuje - v Perlu mu prisly nezbytne. Pozdeji zkusil programovat v Pythonu; dnes na nej neda dopustit, a na Perl si ani nevzpomene.
Re: Reknete Pythonu ne
celé vláknoNapsal jsem jednu netrivialni aplikaci v Pythonu. Reknu Vam, co se mi na Pythonu oproti Perlu nelibilo:
1. Zadne deklarace. Nekdo to povazuje za vyhodu, me to desne chybelo. Hledat chyby v kodu, kde se clovek prepise v nazvu promenne nebo kde zapomene vytvorit promennou pred telem vnoreneho bloku je fakt opruz.
2. Prakticky nepouzitelne defaultni hodnoty parametru funkci. Myslim, ze jednoduchy priklad je dostacujici vysvetleni:
def t (s = []):
s.append (1)
return s
print t()
print t()
3. Nedostacujici uzavery/lambda funkce. Python ma sice konstrukt lambda:, ale v jeho tele muze byt pouze vyraz.
4. Chybejici reference. Chybejici reference znemoznuje napsat neco tak zakladniho, jako je funkce swap.
Tohle jsou vsechno zasadni veci. Pak existuje spousta dalsich mensich problemu jako napr. osklive __identifikatory__, nutnost psat vsude self., chybejici autovivifikace atd.Re: Reknete Pythonu ne
celé vlákno2. Prakticky nepoužitelný příklad. V praxi tohle vůbec není problém, věř mi (nebo mě zkus přesvědčit).
3. Silnější lambda funkce by spousta lidí uvítala. O nějakých praktických problémech s uzávěry ale nevím (opět se nechám přesvědčit).
4. V Pythonu se swap píše a, b = b, a - problém je vyřešen ;). Pythonu má holt některé typy proměnlivé a jiné neměnné. Podle toho se volí hodnoty parametrů. V praxi opět nevidím problém.
Ty __identifikátory__ jsou "ošklivé" záměrně - aby se "magické metody" nepletly s klasickými metodami. Autovivifikace je typický perlismus. Pokud někdo řekne, že potřebuje autovivifikaci, pak ho neuspokojí žádný jiný jazyk. Pro mě to například zase je víceméně nesmyslná vlastnost.
Re: Reknete Pythonu ne
celé vlákno3. Pythonovské uzávěry neposkytují mutable bindings, jen immutable. Ač je přiřazení zlo, občas je nutné (pokud jazyk nemá monády nebo něco podobně ztřěštěného :-)). Pravda je, že zrovna v Pythony tyhle věci na přestřes tak často nepřijdou, ostatně lambda je spíš na výrazy než side-effecting akce, ale týká se to třeba vnořených funkcí.
4. Hmm, to je jen speciální případ. ;-) Ale netuším, jak zrovna tohle souvisí s immutable daty.
Pokud jde o podtržítka, je zajímavé, že třeba SmallTalk se bez nich obejde, a to je charakterově velmi podobný jazyk. Taktéž Ruby. Možná je to ale jen kulturní záležitost... Pravda je, že SmallTalk má velkou výhodu díky kategoriím metod, které umožňují dělat v metodách pořádek trošku jinak. :-)
Re: Reknete Pythonu ne
celé vláknoPokud jde o podtržítka, kdo sleduje vývoj Pythonu, ten ví, že magické metody přibývají snad s každou novou verzí. Určitě by bylo pro vývojáře nemilé, pokud by měli nadefinovanou nějakou metodu, jejíž název se v další verzi zalíbí vývojářům Pythonu a následkem té kolize bude objekt v některých situacích vykazovat podivné chování nebo házet výjimky kvůli odlišnému počtu parametrů. Ano, Python jiný prostředek nenabízí. Jiné jazyky však nenabízejí ani tento.
Re: Reknete Pythonu ne
celé vláknoRe: Reknete Pythonu ne
celé vlákno2. Tenhle priklad je pochopitelne zjednoduseny a ciste pro demonstraci, ale nerekl bych, ze prakticky nepouzitelny. Naopak, nepouzitelna je semantika defaultnich parametru Pythonu. Rozhodne tedy pro cloveka, ktery je zvykly na pekne pouzitelne defaultni parametry z jazyku jako C++ ci Ada.
4. Swap neni jedina vec, kterou absence referenci znemoznuje. Znemoznuje jakoukoliv zmenu promenne primitivniho typu jako vedlejsi efekt. To je pro praci v imperativnim jazyce dosti omezujici.
Re: Reknete Pythonu ne
celé vláknoRe: Reknete Pythonu ne
celé vláknoRe: Reknete Pythonu ne
celé vlákno
def minmax(a, b):
return min(a, b), max(a, b)
a, b = minmax(a, b)
Pokud budu mít složitější program, stejně budu pravděpodobně pracovat se složenými typy a ne s primitivními. Co se týče příkladu na tu implicitní hodnotu, tam není důvod implicitní hodnotu vynechat a případný prázdný seznam posílat explicitně. Jasně, Perl dovoluje každý problém řešit ne dvěma nebo pěti způsoby jako Python, ale dvaceti až padesáti. Toto Python neumožňuje schválně, což však někteří z nás spíše vítají. Pokud má někdo námitku, že nějaký problém v Pythonu špatně řešitelný, pobavme se o tom. Pokud ale námitka zní, že v Perlu nebo některém jiném jazyce to dělá takhle a Python to neumožňuje (ne, skutečně nepotřebuju sahat na parametry funkce pomocí shift ani $_), není to pro mě argument.
Re: Reknete Pythonu ne
celé vlákno1. Ziadne deklaracie ma nijako nerozculuju. Ani v Perle predsa netreba premenne deklarovat. Alebo ako to myslis?
2. Pre pouzitie defaultnych hodnot si zvolil akurat priklad so zoznamom v ktorom to nefunguje. Python vzdy vytvara na zoznamy referencie a z toho plynie aj spravanie funkcie t(). Ak ju zavolas s argumentom prazdnym alebo neprazdnym zoznamom, bude fungovat, tak ako ocakavas, napr:
print t([]) print t([]) print t(t([])) print t(['a','b']) print t(['x'])Toto ako zaobchadza Python s listami ma tiez netesi, lebo pri priradeni list2=list1 sa vytvori len nova referencia na ten isty list. Ak chce clovek vytvorit novy list ako kopiu stareho treba urobit list2=list1[:]
Inac ale defaultne hodnoty vo funkciach prakticky funguju, napr:
def halo(meno="Vaclav"):
return "Halo %s" % meno
print halo()
print halo ('MikRom')
3. Lambda funkcie neposkytuju taku funkcionalitu ako pomenovane funkcie - ano s tym suhlasim, ale Guido sam nema zrejme lambdy rad a chcel ich v Pythone 3000 povodne aj zrusit. Zrejme si mysli, ze sa moc nepouzivaju.
4. Ze referencie nechybaju, toho dokazom je tvoj priklad s funkciou t(). Na zoznamy sa vzdy pouzivaju referencie. Swap tiez funguje
l1=['a','b'] l2=['x','y'] print "l1=%s, l2=%s" % (l1, l2) l1, l2 = l2, l1 print "l1=%s, l2=%s" % (l1, l2)Ina vec je, ze netreba explicitne dereferencovat ako v Perle. Ale to pracu so zlozitejsimi strukturami podla mna skor zjednodusuje.
5. __identifikatory__: Ano v Pythone si treba zapamatat co znamena
if __name__ == "__main__": ...ale je to podobne ako vediet v Perle, co to je $_,@_,...
6. self: Python prostrednictvom self pri premennej, resp. funkcii rozlisuje, ci sa jedna o atribut, resp. metodu aktualneho objektu, alebo o nejaky globalny identifikator (ak tam self nie je). Self je vlastne referencia na slovnik, ktory reprezentuje dany objekt. Identifikator self pochadza z Perlu. Python prebral z Perlu sposob, ze objekty su reprezentovane cez asociativne polia (t.j. slovniky). A v Perle sa tiez doporucuje odkaz na aktualny objekt oznacovat ako $self.
Re: Reknete Pythonu ne
celé vlákno2. To jsem zvolil, protoze se mi ten priklad pak vejde na 6 radek. To same plati i pro objekty.
Re: Reknete Pythonu ne
celé vláknoAno "use strict" sa doporucuje, ja to tiez pouzivam, ale nie som si isty, ci to pouziva kazdy :-)
Python: Myths about Indentation
celé vláknoVynutene odsadzovanie ma aj svoje vyhody - precitaj si napriklad toto: Python: Myths about Indentation
Re: Reknete Perlu ne
celé vláknoDekuji za radu, ale rozhodl jsem se ji nenasledovat.
Re: Reknete Perlu ne
celé vlákno
def generuj_soucet(a,b):
yield 'print '+str(a)+'+'+str(b)
def generuj_funkci_soucet(x,y):
yield 'def soucet('+str(x)+','+str(y)+')'
for s in generuj_soucet(a,b):
yield ' '+s
for s in generuj_soucet(1,2):
print s
for s in generuj_funkci_soucet('cislo1','cislo2'):
print s
Pak muzete generator generuj_soucet pouzit na obou urovnich, a budete mit zarovnani spravne, jak ukazuje funkce generuj_funkci_soucet.
Re: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknoNevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce. Nevim, jak byste to chtel delat cisteji bez retezcu, asi by zase pomohl nejaky priklad. Vyse uvedeny program si navic nedava vyssi ambice, nez byt kratkou ilustraci toho, o cem autor tvrdil, ze to neni mozne.
Re: Reknete Perlu ne
celé vláknoTomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest?Jako přes eval? A co když ten jazyk používá inkrementální in-memory kompilátor, jako třeba všelijaké mutace Lispu? to ho budete pokaždé znovu kompilovat? ;-)
A generovat kod, ktery bude dale nekdo upravovat rucne, mi nepripada zrovna dobry napad (z hlediska spravy).Proč? To nepoužíváte kompilátory? Nikdo snad neříká, že by se ručně upravoval vygenerovaný kód, takoví šílenci snad už vyhynuli. Pokud generátor vytváří správný výstup, není třeba vrtat se v jeho výstupu - přece když potřebuju upravit program, taky se nevrtám ve strojáku hexeditorem, ale upravím zdrojový kód a zrekompiluju ho. Nevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce. Ehm, řetězce? Už jste slyšel o syntaktickych stromech? A o jejich transformátorech? Nebo třeba o partial application? Pokud vím, partial application používá třeba Psyco.
Re: Reknete Perlu ne
celé vláknoO AST vim, ale pokud by ten dotycny generoval primo AST (a ja bych to mimochodem delal take tak, ale v Pythonu pro to skutecne nevidim zadny duvod), pak by samozrejme problemy s whitespace asi nemel. ;-)
Re: Reknete Perlu ne
celé vláknoPokud kod generujete za behu, tak se urcitym krokum (jako je kompilace) nevyhnete. Pokud se jim totiz dokazete vyhnout, nemusite to resit za behu.Tak tomuhle nerozumím. Nebyl by nějaký příklad?
Re: Reknete Perlu ne
celé vláknoTomu moc nerozumim. Neni proste v dynamickem jazyce lepsi, nez ten kod vygenerovat, ho rovnou provest?Jako přes eval? A co když ten jazyk používá inkrementální in-memory kompilátor, jako třeba všelijaké mutace Lispu? to ho budete pokaždé znovu kompilovat? ;-)
A generovat kod, ktery bude dale nekdo upravovat rucne, mi nepripada zrovna dobry napad (z hlediska spravy).
Nikdo snad neříká, že by se ručně upravoval vygenerovaný kód, takoví šílenci snad už vyhynuli. Pokud generátor vytváří správný výstup, není třeba se vůbec vrtat v jeho výstupu - přece když potřebuju upravit program, taky se nevrtám ve strojáku hexeditorem, ale upravím zdrojový kód a zrekompiluju ho.
Nevim co nazyvate "cistym zpusobem generovani kodu" - kod (ve smyslu zdrojak) jsou prece retezce.Ehm, řetězce? Už jste slyšel o syntaktickych stromech? A o jejich transformátorech? Nebo třeba o partial application? Pokud vím, partial application používá třeba Psyco. Techniky jako partial application dále stírají rozdíly mezi kompilátory a interprety a přitom můžou často vyžadovat generování kódu za chodu, s tím, že za to něco přinesou - v případě Psyca třeba ten výkon. :-)
Probém je, kam to generování napasujete. Pokud jazyk AST nějakým způsobem neexponuje (což většina jazyků nedělá), holt se člověk musí uchýlit ke generování textu. Tím sice nenapíšete něco jako Psyco, ale něco jako třeba ESQL už ano, a i k takovým věcem se generování kódu často používá. Nebo třeba AOP, pokud to jazyk neumí lepšími prostředky, jako je třeba metaobjektový protokol. Ale určitě má smysl tyhle věci dělat.
Re: Reknete Perlu ne
celé vláknoPokud mate na mysli "z Pythonu generuji dalsi Python", pak to muze byt lepsi - ale stejne nemusi.
Priklady:
a. Generovani kodu muze byt cast "build" procesu. Nikoliv dynamicky za behu aplikace, ale dynamicky z makefilu.
b. Proc bych nemohl Python generovat z jineho jazyka? Napriklad z C aplikace? Napriklad protoze ke generovani kodu musim analyzovat velke mnozstvi dat a mam na to v C hotove a odladene knihovny?
c. A z druhe strany, proc bych nemohl Python generovat ze skriptu nebo treba z sqlplus? Zejmena *tady* mam problem s nejakym globalnim trackovanim hloubky vnoreni.
Re: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknoPokud vase druha veta naznacuje, ze by snad generovany kod mel byt "spravne strukturovany" a ze by to nemel byt "jeden velky skript", pak nechapu proc. Vystup z lexu nebo yaccu snad hezky a strukturovany je? Proc by mel vubec byt?
Re: Reknete Perlu ne
celé vlákno1. Nadeklarujeme FUNCSTACK = []. Volající zavolá podřízený generátor, ten vygeneruje funkci stackFunc(). Volající udělá FUNCSTACK.append(stackFunc()). Toto udělá nadřízený generátor kolikrát potřebuje, vybere si funkce ve své funkci třeba pomocí FUNCSTACK.pop() a volá je podle potřeby. Takto si nikdo žádný globální stav pamatovat nemusí; jediný globální stav je v globální proměné FUNCSTACK.
2. Volající si pamatuje jenom svůj lokální stav a indentuje o jednu úroveň přijatý kód od volaného, kdykoliv je potřeba.
Re: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vlákno
class Generator(object):
def __init__(self):
self.codeRows = []
def indent(self):
self.add('$I')
def detent(self):
self.add('$D')
def add(self, row):
self.codeRows.append(row)
def process(self):
indentLevel = 0
indentedRows = []
for row in self.codeRows:
if row == '$I':
indentLevel += 1
elif row == '$D':
indentLevel -= 1
else:
indentedRows.append(indentLevel * 4 * ' ' + row)
exec '\n'.join(indentedRows)
g = Generator()
g.add('print "Zaciname"')
g.add('for a in xrange(3):')
g.indent()
g.add('for b in xrange(4):')
g.indent()
g.add('print a * b')
g.detent()
g.detent()
g.add('print "Vse v poradku"')
g.process()
Řešení č. 4: Nasazení preprocesoru případně i v kombinaci s řešením č. 3.
Re: Reknete Perlu ne
celé vlákno
def process_code(code):
indentLevel = 0
indentedRows = []
for row in (r.strip() for r in code.split('\n')):
if (not row):
continue
if row == 'BEGIN':
indentLevel += 1
elif row == 'END':
indentLevel -= 1
else:
indentedRows.append(indentLevel * 4 * ' ' + row)
return '\n'.join(indentedRows)
exec process_code('''
print "Zaciname"
for a in xrange(3):
BEGIN
for b in xrange(4):
BEGIN
print a * b
END
END
print "Vse v poradku"
''')
Re: Reknete Perlu ne
celé vlákno
def process_code(code):
indentLevel = 0
indentedRows = []
for row in (r.strip() for r in code.split('\n')):
if (not row):
continue
if row == 'BEGIN':
indentLevel += 1
elif row == 'END':
indentLevel -= 1
else:
indentedRows.append(indentLevel * ' ' + row)
return '\n'.join(indentedRows)
exec process_code('''
print "Kaslu na level"
for a in xrange(3):
BEGIN
for b in xrange(4):
BEGIN
print a * b
END
END
print "Vse v poradku"
''')
Tak co, Petře, furt problémy?
Re: Reknete Perlu ne
celé vláknoPanove, musim vam neco duleziteho rict. Ne ze bych vam chtel v necem branit, to by me ani ve snu. Jen me to tak napadlo, ... mozna je to malickost, bezvyznamny detail. Ale dobra, kdyz ven s tim tak ven s tim.
Jste s touhle diskusi celkem brutalne off-topic.:D
Re: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknoRe: Reknete Perlu ne
celé vláknoSmyslem meho argumentu bylo, ze existuji niche, ve kterych Python bidne hyne zatimco Perl si jich uziva. Implicitne pak tvrdim, ze na zaklade toho je Perl obecnejsi a ma vyssi hodnotu (a ted kvantifikuji, napriklad pro me). Nevyslovena premisa konecne je, ze neexistuje niche, ve kterem prezije Python a ne Perl.
Re: Reknete Perlu ne
celé vláknoNavic, opravdu nic nebrani tomu, generovat z te aplikace jenom nejaky mezivysledek, ktery se pote Pythonem zpracuje nebo zkompiluje (i kdyby slo jen o pridani nejakych znacek zacatek a konec bloku, ale ja bych spis vytahl z te aplikace co vlastne chce a kod vygeneroval Pythonem). Tam uz si to zarovnani pamatovat lze. Nakonec tim usetrite cas, protoze pokud je jazyk, z ktereho chcete ten Python generovat, natolik dementni, ze si nemuzete pamatovat odsazeni, pak si co nejrychlejsim prechodem do Pythonu praci jen usnadnite. :)
Predchozi odstavec plati i pro Perl, samozrejme.
Perl a Python jsou prinejmensim ekvivalentni jazyky (to spis Python ma sirsi zaber, protoze treba takovy Blender nebo Maya skriptovani v Perlu neumoznuje). Takze asi tezko najdete situaci, kde by se dal pouzit jenom Perl.
Re: Reknete Perlu ne
celé vláknoDiky ...
celé vláknoTesim se na prokladani praktictejsimi kapitolami.
Vytrvejte! ;-)
Re: Diky ...
celé vláknoRe: Diky ...
celé vláknoRe: Diky ...
celé vláknoJedine, co se mi na tom nelibi, jsou scrollbary, jelikoz misty mi ten pre blok pretejka horizontalni rozmer clanku. To ale hraje jen pro "pre" teorii, jelikoz bez toho tagu by se browser pokusil zalamovat slova.
Mozna je neco spatne ve Vasem prohlizeci, nebo mozna nejakym zahadnym zpusobem dostavate z roota jiny clanek nebo style sheet nez ja.
Re: Diky ...
celé vláknoJe to pro jistotu, po vas to samozrejme bude jeste nekdo cist, ale aby se treba v casove tisni na takovou "malickost" nezapomelo (jako jednou davno v mem pripade, ale to byla moje chyba, protoze davam clanky na posledni chvili a chudak sefredaktor :-).
Re: Diky ...
celé vláknoTady máte screenshot:
http://img519.imageshack.us/img519/254/rootqx2.png
Re: Diky ...
celé vláknoNapriklad clanek
http://www.root.cz/clanky/hratky-z-radky-kombinace-procesu-podruhe/
pouziva ty same PRE tagy jako muj, ten se vam zobrazi jak?
Dival jsem se do zdrojovych kodu clanku (online verzi) a PRE tagy tam jsou. A ve stylesheetu je monospace "cerne na bilem", tak opravdu nevim v cem je problem. Ptal jsem se na to i v redakci a pochodil jsem stejne - jim se zobrazuje clanek spravne a navic mezi PRE a CODE-AREA necini rozdil (krom toho ze CODE-AREA ma zvlastni ramecek). Navic CODE-AREA je pouze interni tag a nepatri do html.
Takze v podstate nevim co mam delat, aby bylo PRE jeste vic PREformatovane nez ted. :)

