Ten whitespace, ktery zde neni zanedbatelny - se tokenizuje nebo zpracovava jak (prakticky / akademicky) ?
Prijde mi to jako nechutny hack, ktery nutne musi porusovat rozdeleni do syntaktickych a semantickych vrstev parsovani zdrojaku pro vysledny AST.
Jesteze za meho studia na VUT jsme takoveto bleh jazyky nemuseli zpracovavat v predmetu s prekladaci :-) A ani ted... po 20 letech nechapu proc nekdo vubec pouziva Python. Uz jen potreba specialniho editoru, co by umel odsazovat bloky je pro me showstopper.
Jako INDENT (zacatek odsazeneho bloku) a DEDENT (konec odsazeneho bloku).
> jak (prakticky / akademicky) ?
nevim co znamena akademicky, prakticky tokenizer sleduje pocet mezer na zacatku radku, pokud je vetsi nez predchozi, vlozi INDENT, pokud mensi nez predchozi a odpovida nektere z predchozich urovni odsazeni, vlozi odpovidajici pocet DEDENT. Pokud je mensi, ale neodpovida zadne z predchozich urovni, vyhodi vyjimku.
https://github.com/python/cpython/blob/3.10/Lib/tokenize.py#L509
uvnitr zavorek a viceradkovych retezcu je odsazeni ignorovano
S Pythonem jsem se naštěstí setkal jen jednou (opravoval jsem bug v jakémsi SW) a stačilo mi to na celý život. Bohužel, tuhle zhůvěřilost s významným whitespace převzal YAML a s tím se člověk občas potkává i když nechce :-(
YAML je ovšem ještě horší věc. V Pythonu, když už není na obrazovce vidět, kde začíná blok (odsazení), tak je jasný, že se musí refaktorovat a ideálně mít celý blok až na první úroveň celý na obrazovce, nikdy ne delší.
Jenže do YAMLu se ukládá konfigurace, tam se refaktorovat nedá a já tam fakt dost často nevidím, kolik těch mezer mám narvat. Proti tomu je Python zlatý :-)
* aneb když někdo něco slepě okopíruje a nepřemýšlí u toho
Ano, whitespacy nejsou jediný problém YAMLu. Bohužel se postupně prosazuje přesně podle přírodního zákona, že se nakonec prosadí to nejhorší řešení :-(
Co je na něm tak špatného? Já se k YAMLu dostal díky Home Assistentu a ESPHome. Na takovéto konfigurace mi to přijde mnohem lepší než JSON, XML a INI. Editor VSCode ukazuje barevně levely odsazení takže se v tom lehce orientuje. Ale asi jsem se nikdy nedostal k nějakému extrémně dlouhému a složitému YAMLu jako vy.
YAMl je ako bojove plemeno psa. Ked je to male tak je to zlate a mile, lahko citatelne. No ked to vyrastie tak sa s toho stane neprimna a nezepecna obluda.
Ale viete ze YAML je 'nadstavba' nad JSON takze mozete kludne pouzivat JSON zapisy cez {} a [].
A este vam prezradim dalsie velke tajomstvo skute si v specifikacii pohladat & a *.
Jaka jsou lepsi reseni? Ja na tohle nemam vyhraneny nazor. JSON je moc jednoduchy, XML zase zbytecne komplikovane. Mozna TOML?
Mně přijde YAML použitelné - dá se použít jako vylepšený JSON (podporuje komentáře, trailing comma), dá se validovat pomocí JSON schema... TOML bude v Pythonu od 3.11 ve standardní knihovně, takže o důvod víc se nad ním zamyslet. JSON a XML nebrat, samozřejmě.
Tak nějak, YAML je celkem v pohodě, je to čitelné a dá se s tím rozumně pracovat, převádět to na jiné formáty (JSON, netypované asociativní pole...), navíc se to dost rozlezlo (GitHub Actions, OpenAPI aka Swagger...), takže člověk se tomu stejně moc nevyhne.
Divne, ze ve standardni knihovne dosud nebyl, kdyz pyproject.toml je soucasti specifikace definovan v PEP 517.
na druhou stranu to ma aspon typ "date" (resp. timestamp), na rozdil on mnoha ostatnich formatu, kde se s tim neparou a tlaci to pres stringy ;)
jo zrovna ten to tak taky ma = a "lidova tvorivost" ve zpusobu ukladani dat a timestampu je nekonecna (a to nemluvim o tom, ze tech par bajtu navic na ulozeni TZ taky nikoho nezbije, ano divam se na vyvojare z te zeme, kde maji posun TZ o par hodin + navic jeste 30 minut :)
Nastavte si editor tak, aby Vam nedovolil odsadit pres mimo povoleny level. Treba Emacs to tak ma defaultne.
nestaci si pocitat ":" a prazdne radky, aby to nebylo tak slozite? Jinak z hlediska lexeru je to zvlastni, to je pravda
Mno v podstate se tam neco podobneho uvnitr deje, protoze si tokenizer musi pamatovat, kolik bloku pripadne ukoncit (DEDENT) kdyz najde prazdny radek + neodsazeny dalsi radek. Je to hack, jak se pise vys.
Mozna pro zacatek bloku by to stacilo, pro ukonceni bloku nestaci, tam je treba zjistit, o kolik urovni se vracite.
Ten kod tokenizeru je celkem trivialni, odpovedel jsem v jinem komentari, ktery (dosud?) neprosel moderaci.
Trosku se k tomu vratim priste, ale je to reseno skutecne hackem - konkretne tokeny INDENT a DEDENT. V beznych jazycich by tokenizer delal vlastne jen tokeny pro { a } nebo BEGIN/END, tady ma "stav" pro hlidani indentace, proste hack.
Ale vůbec ne, prostě jen namísto klasického lexeru tam je lexer s hackem - pamatováním stavu*. Jestli je to dobře nebo špatně, to těžko posoudím, protože prakticky v každé naší aplikaci/službě nějaký takový hack máme taky :-)
* tedy i klasický lexer si většinou musí něco pamatovat, typicky aspoň jeden "budoucí" znak nebo to musí umět knihovna, kterou používá (ungetc() nebo podobně).
Pokud je problém v tom, že nejde použít Lex nebo něco takhle standardního, chápu, že to může být nepříjemné, jinak ale myslím, že je to prkotina. Podstatné je, zda syntakticky významné odsazování je výhoda tady uznávám, že to je sporné.
Pred takmer 20 rokmi som kvoli tomu Python zaznaval, ale zivotne skusenosti ma naucili, ze takto to je v skutocnosti lepsie, lebo prasaci prasia o cosi menej. A potom sa vyskytne nejaky ind, ktory odsadi riadok zmiesancami tabulatorov a space a zase sa potvrdi, ze vynaliezavost nepozna hranice.
Rád bych upozornil, že třeba takový Haskell to má taky tak, a není s tím žádný zvláštní problém. Prostě se to parsuje. Když máte dostatečně inteligentní nástroj, jako třeba https://hackage.haskell.org/package/parsec je odsazování pomocí whitechars prostě jen další logika.
Ukladat logiku do whitespace je iste skvely napad nepodobny brainfucku. Ja by som sa nebranil, podme dalej. Skusme vymysliet este aj kombinacie medzery, tvrdej medzery a TABu. To by vzdy mohlo robit nieco zaujimave.
To ze odsadenie 'pomaha' ludskemu oku lepsie sa orientovat v strukturovanom texte neznamena ze je to aj dobry napad na ukladanie logiky lebo prave tak sa tam moze aj nieco nenapadne stratit.
Tak ona to logika nie je, ale identifikacia blokov.
K TABom, tie boli vymyslene(uz na mechanickych strojoch) pre zarovnanie nie pre odsadenie
Jazyky jako Haskell a coffeescript maji o dost komplikovanejsi odsazovaci pravidla. V Pythonu je situace zjednodusena rozlisenim vyrazu (expressions) a prikazu (statements), coz prinasi mnoha omezeni, ale dost zjednodusuje pravidla odsazovani.
Jo, v roce 2022, kdy máme k dispozici asi 100 různých editorů, které tohle v pohodě umějí, je to hrozný problém. Jsi zaujatý, prostě to řešení má výhody a nevýhody a stačilo by napsat "mně to nevyhovuje". Ale to by nebylo cool.
@RDa
To nechápu. Připsaní snad každého jazyku odstazujete bloky, dokonce i pokud se používají ty slavné závorky. Pokud je někdo prase, tak je úplně jedno jestli se pouze odsazuje, nebo se použijí i závorky - např. javascript a nebo lisp, že. A napsat spaghetti traktát bez odsazení od shora až dolů, to je taky úžasné.
Proč někdo používá Python? Třeba proto kolik obsahuje knihoven v kombinaci s dynamickým typováním a celkem bezproblémovou exekucí skriptů. Na ad-hoc stahování dat z různých API a mixování statistik je úplně ideální.
Stačí jeden skript. Když zabrousíte na stránky NASA, i automatický formater najdete ;-) :-D
6. 8. 2022, 13:43 editováno autorem komentáře
Klasika, odsadzovanie vadí hlavne tým, ktorí Python nepoužívajú. :)
Mimochodom, ku Pythonu a F# sa nedávno pridala aj Scala 3. Kód bez zložených zátvoriek vyzerá oveľa lepšie.
package checkbox
import javafx.application.{Application, Platform}
import javafx.event.{ActionEvent, EventHandler}
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.CheckBox
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.scene.layout.HBox
class CheckBoxApp extends Application {
override def start(stage: Stage): Unit =
stage.setTitle("CheckBox")
val cbox = new CheckBox("Show title")
cbox.setSelected(true)
cbox.setOnAction((_: ActionEvent) => {
if cbox.isSelected() then
stage.setTitle("CheckBox")
else
stage.setTitle("")
})
val root = new HBox
root.setPadding(new Insets(25))
root.getChildren.add(cbox)
stage.setScene(new Scene(root, 400, 300))
stage.show()
}
@main
def main(): Unit =
Application.launch(classOf[CheckBoxApp])
“Kód bez zložených zátvoriek vyzerá oveľa lepšie.”
To je možné, ale jde to i bez toho, aby odsazení ovlivňovalo syntaktickou správnost kódu.
Logicky, nebudu přece používat jazyk, který používám za braindamaged :-D
Mě ten kód přijde docela nepřehledný. A složené závorky v něm přesto jsou :-D
V Scale 3 sú zložené zátvorky voliteľné. Tak nakoniec možno v danom príklade odstrániť všetky zložené zátvorky:
package checkbox
import javafx.application.{Application, Platform}
import javafx.event.{ActionEvent, EventHandler}
import javafx.geometry.Insets
import javafx.scene.Scene
import javafx.scene.control.CheckBox
import javafx.scene.layout.StackPane
import javafx.stage.Stage
import javafx.scene.layout.HBox
class CheckBoxApp extends Application:
override def start(stage: Stage): Unit =
stage.setTitle("CheckBox")
val cbox = new CheckBox("Show title")
cbox.setSelected(true)
cbox.setOnAction((_: ActionEvent) =>
if cbox.isSelected() then
stage.setTitle("CheckBox")
else
stage.setTitle("")
)
val root = new HBox
root.setPadding(new Insets(25))
root.getChildren.add(cbox)
stage.setScene(new Scene(root, 400, 300))
stage.show()
@main
def main(): Unit =
Application.launch(classOf[CheckBoxApp])
Mne to nepripadá neprehľadné, tu to na roote vyzerá (všeobecne) kód horšie , ale v textovom editore je to fajn. Jediné s čím som sa stretol je, že automatické formátovanie kódu je náročnejšie a nefunguje vždy dobre.
F# napríklad má aj verbose syntax, kde sa blok môže ukončiť kľúčovým slovom done, ale rovnomerné odsadenie sa vyžaduje stále.
for n in 2..12 do
printfn "%i" n
printfn "%i" (n * n)
done
for n in 2..12 do
printfn "%i" n
printfn "%i" (n * n)