Ty dva ify v sobě jsou nečitelné hlavně proto, že autor nepoužil závorku k vyjasnění struktury ve výrazu - závorka dost podle mě pomůže:
converted = ["negative" if x < 0 else ("positive" if x > 0 else "zero") for x in values]
Dokonce můžeš napsat třeba tohle, tam nevidím žádnou nejasnost:
converted = [ "negative" if x < 0 else "positive" if x > 0 else "zero" for x in values ]
Pro složitější věci lze vždycky napsat funkci a pak ji použít.
Konkrétně je obojí kupa hnoje. První zápis bych asi ještě zkousnul. Ale zapsat to na více řádků mě přijde jako úplný nesmysl. Tam postrádám jediný rozumný důvod proč nepoužít for a vnořené if. Navíc je to ještě nečitelnější než bez jakýchkoliv závorek.
l = [] for x in values if x < 0: l.append("negative") elif x > 0: l.append(""positive") else: l.append("zero")
nebo ješte lépe, jak bych to udělal:
def foo(x): if x < 0: return "negative" elif x > 0: return ""positive" else: return "zero" converted = [foo(x) for x in values]
nazývá se generátorová notace, což je poněkud nepřesně přeložený anglický termín (list/tuple) comprehension
No tak tenhle český výraz vidím prvně a není nepřesný, ale úplně špatný. Když už tak generátorovou notaci bych přiřadil jenom k generator comprehension ale určitě ne k list nebo dict. A co koukám do dokumentace, tak se tam vždy píše o generator expression a list comprehension viz: https://docs.python.org/3.13/howto/functional.html#generator-expressions-and-list-comprehensions
Ještě jedna věc, kterou jsem nedávno objevil, když jsem potřeboval udělat typ k nějaké složitější funkci a s Callable
to prostě nešlo (nebo to bylo šílené) . Lze použít typing.Protocol
https://docs.python.org/3/library/typing.html#typing.Protocol
class Ask(Protocol): def __call__(self, question: str, default: str | None = "yes") -> bool: ... def foo(call: Ask): call("something")
plně souhlasím, že to není dobře přeložený termín, ale zrovna ve světě Pythonu se to snaží takto prosadit (http://diveintopython3.py.cz/comprehensions.html#listcomprehension, https://coobas.gitlab.io/python-fjfi/posts/iteratory-a-generatory.html#Gener%C3%A1torov%C3%A1-notace). V tomto případě bych asi zůstal u původního list comprehension nebo ještě lépe - prostě používat map a filter :) [ale to není idiomatické, vím, vím]
Absolútne súhlasím s názorom Sailjacka, že ten výraz nie je len nepresný, ale je úplne nesprávny.
To, že sa niekto snaží niečo presadiť, aj keby sa to malo diať dlhodobo, vôbec neznamená, že sa to má nasledovať, zvlášť pokiaľ je to nesprávne.
Prekladanie termínov ako také je pritom podľa mňa potrebné, lebo môže odstrániť jednu úroveň zložitosti v chápaní preberanej látky. Takže ja osobne to podporujem aj veľmi oceňujem a to napriek tomu, že s angličtinou naozaj problém nemám.
Je ale nutné, aby preklady neboli otrocké a aby vychádzali z nejakého kontextu.
Ten kontext existuje a zvyčajne presahuje do iných oborov, pre náš obor väčšinou asi do matematiky.
Podľa výsledkov krátkeho hľadania, na základe rýchleho preletenia textom, keď sa toto konkrétne riešilo v roku 2010, tak v diskusii bol odkaz, že to má v pythone pripomínať zápis definície množín, kde sú uvedené aj vlastnosti jednotlivých členov. Takže preklad by mal vychádzať z toho a nie z prekladu slov alebo z toho, že sa tam niekedy používa nejaký generátor, ktorý s tým pritom ale vôbec nijako nesúvisí, ten predsa môže byť použitý aj v cykle. Teda aspoň si to myslím, v pythone som už dávno nepísal ;-)
Podobne, aj v nejakom dávnejšom článku som si všimol odkaz na preklad point free alebo tacit programming. To prvé má tiež pôvod v matematike a má to tam nejaký význam. To druhé v latinčine, tak ako enormné kvantum výrazov, ktoré v IT, aj v bežnom jazyku dlhodobo používame.
Jednoducho, keď je nejaký termín použítý v nejakom novom obore nemusí to vôbec znamenať, že bol v tom novom obore použitý ako v prvom.
Nejaký kontext jednoducho v tom pôvodnom nepreloženom názve je, niečo sa nejako volá, lebo sa to podobá na niečo, čo sa dlhodobo používa inde, ľudia, ktorí to v origináli nejako pomenovali v tom vidia nejakú spojitosť a asi to v čase pomenovania chápali tak, že daná spojitosť prispieva k pochopeniu látky a umožňuje vidieť ten nový koncept v súvislostiach s pôvodným konceptom.
A ešte na záver, podľa môjho skromného názoru, preklad naozaj nemusí obsahovať rovnaký alebo menší počet slov a ani nemusí mať slová v rovnakom poradí, zvlášť ak majú dva jazyky iné pravidlá. Preklad má byť jednoducho zrozumiteľný a popisovať to, čo pojem znamená.
Tady jsou příklady témat, co jsem měl na mysli:
https://leanprover.github.io/talks/IFL2019.pdf
https://arxiv.org/pdf/1908.05647.pdf
https://dl.acm.org/doi/pdf/10.1145/3547640
Ta lokální imperativita přeskládá kód s mutabilními proměnnými do “do” bloků (pomocí bind) v čistě funkcionálním jazyce. A ten FBIP zaručí čistě funkcionální datové struktury s výkonem mutabilních (když je refcount 1). Pokud jsou všechny funkce totální a všechny typy induktivní, znamená to, že program vždy skončí a zaručeně nemá memory leaky. Což jinak zaručí jen tracing GC, akorát že nedeterministicky. Jsem k dispozici k případným dotazům :)
Keď som sa prvý krát bližšie zoznámil s list comprehensions v Pythone, tak som si pomyslel, aká super vec!
O pár rokov neskôr som narazil na F# a tam mi spadla sánka. Ten obsahuje bezhraničné možnosti spracovania dátových štruktúr. Python je len slabý odvar možností funkcionálneho programovania a aj to je zakamuflované kdesi v nič nehovoriacich moduloch ako itertools.
(Aj tak asi väčšina programátorov používa Pandas a pod. a nie built-in funkcie.)
Odtedy som presedlal na F# a Groovy keď treba pokročilú dátovú analýzu. Oba jazyky majú priamo zabudované funkcie a navyše query výrazy. (Ginq v Groovy je inšpirovaný LINQom zo C#.)
Groovy príklad
def numbers = [0, 1, 2, -3, -1, 9] def res = GQ { from n in numbers where n > 0 orderby n in desc select n } println res def res2 = numbers.findAll { it > 0 }.sort { a, b -> b <=> a } println res2
F# príklad
type User = { FirstName: string LastName: string Occupation: string Salary: int } let users = [ { FirstName="Robert"; LastName="Novak"; Occupation="teacher"; Salary=1770 } { FirstName="John"; LastName="Doe"; Occupation="gardener"; Salary=1230 } { FirstName="Lucy"; LastName="Novak"; Occupation="accountant"; Salary=670 } { FirstName="Ben"; LastName="Walter"; Occupation="teacher"; Salary=2050 } { FirstName="Robin"; LastName="Brown"; Occupation="bartender"; Salary=2300 } { FirstName="Amy"; LastName="Doe"; Occupation="technician"; Salary=1250 } { FirstName="Joe"; LastName="Draker"; Occupation="musician"; Salary=1190 } { FirstName="Janet"; LastName="Doe"; Occupation="actor"; Salary=980 } { FirstName="Peter"; LastName="Novak"; Occupation="singer"; Salary=990 } { FirstName="Albert"; LastName="Novak"; Occupation="teacher"; Salary=1930 } ] let users2 = users |> List.map (fun e -> {| FirstName = e.FirstName LastName = e.LastName |}) users2 |> List.take 3 |> List.iter (printfn "%A") printfn "---------------------" query { for user in users do select {| FirstName = user.FirstName; LastName = user.LastName |} take 3 } |> Seq.iter (printfn "%A")
Budem piť Bud light keď môžem Prazdroj?
Pozor na to, že map i filter vrací generátor (tuším, že ke změně došlo mezi py2 a py3). A obsah generátoru se vyhodnocuje líně, až ve chvíli, kdy je to nezbytně potřeba. I proto jsou demonstrační příklady plné list()ů. Takže jednak přes výsledek nepůjde iterovat dvakrát...
>>> g = map(lambda x: x, range(10)) >>> list(g) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> list(g) []
... druhak, pokud map-ujete něco, co má svůj stav, výsledek nebude odpovídat stavu, kdy byl generátor vytvořený, ale stavu, kdy byl rozbalený. Já vím, není to funkcionální, ale mohlo by to překvapit.
>>> class Multiplier: ... def __init__(self, by): ... self.by = by ... def __call__(self, number): ... return self.by * number ... >>> m = Multiplier(1) >>> num_in = list(range(5)) >>> num_out = map(m, num_in) >>> m.by = 7 >>> list(num_out) [0, 7, 14, 21, 28] >>> num_out = map(m, num_in) >>> num_in.append(11) >>> list(num_out) [0, 7, 14, 21, 28, 77]
E: oprava vyšinutí z větné stavby
27. 7. 2023, 16:58 editováno autorem komentáře
U světla, tykat prosím, děkuju Vám :)
Jo, jde to napsat líp, a já bych takhle map dobrovolně nepoužil, ale programátoři (a skoro bych řekl zejména v pythonu) jsou různí. Kdo ví, nedokážu si představit, že by "mutabilní map" byl k něčemu dobrý, ale nehodlám kategoricky tvrdit, že taková situace nenastane.
Nebavím se o seminárkách, ale o firmách se stovkami tisíc řádků kódu. U nás jsme třeba začali a na Redditu těch lidí, kteří si to nemůžou vynachválit, psala spousta. Pravdou je, že každý může mít tu motivaci jinou - někdo řeší korektnost (mypy/pydantic), někdo chce optimalizaci (mypyc/lpython), někdo jiný zase staví weby na FastAPI. Už i obyčejné dataclassy jsou postavené na typových anotacích.
Já si to nevymyslel, takový modul se připravuje roky a musí být přiměřeně konzervativní. Přišel jsem už k hotovému. Julia by byla určitě lepší, ale to při troše štěstí až s dalším updatem někdy za 10 let. (Je to na Open University).
Nicméně pokud se chytí ten LPython a třeba i Mojo, tak by to mohlo zůstat jako schůdná alternativa.
Mně to pro čisté funkce ve smyslu https://en.wikipedia.org/wiki/Pure_function přijde v pořádku. Otázka definice nebo je i s nimi problém?
Kdyby chtěl někdo vidět kód (à la ML), tak funkce
def decBy1 : Nat -> Nat
-- Nat = {0, 1, 2, ...}
není totální, protože není definovaná pro nulu.
Totality se dá dosáhnout rozšířením návratové hodnoty na součtový typ:
def decBy1 : Nat -> Option Nat
| .succ n => .some n
| .zero => .none
Nebo zúžením def. oboru funkce:
def decBy1 (n : Nat) (_ : n≠0) : Nat :=
match n with
| .succ n => n
Memoizace pak bude fungovat pro obě funkce, v tom druhém případě se nebudou ukládat neplatné vstupy (a výsledek se nemusí vázat přes Kleisliho nesmysle).
To je narážka na to, že tomu rozumí jen 1% vývojářů (když vynecháme frontend, tak 2%). Ten zbytek svou ignoranci omlouvá tím, že to označuje za zbytečné nesmysly.
A poněkud vážněji, je nesmysl používat zbytečně složitou a abstraktní konstrukci (i když jinde se může náramně hodit, sama o sobě tedy nesmyslem není), když existuje jednodušší a čitelnější řešení, jehož podstatu každý zná ze ZŠ matematiky (i když plné pochopení toho, co se pak odehrává v rámci statické kontroly, překladu a za běhu zas tak jednoduché není, ale pořád o řád lepší než Kleisli).
Pěkný úvod. A v diskuzi taky pěkné příspěvky.
V kapitole 11 mi přijde takové zbytečné a matoucí "Můžeme použít i uživatelskou funkci s jedním parametrem (a jednou výstupní hodnotou – ovšem lze využít i implicitní hodnotu None)."
Výstupní hodnota bude vždy jen jedna, což je ostatně řečeno už v kapitole 7 a tady by se to dalo krásně ukázat.
U vstupních parametrů by mě mátlo, že jde použít i funkce, která používá více parametrů, akorát pojmenovaných.