Ja bych rad doplnil jeste druhou moznost, ktera mi pri caste praci s Pythonem prijde mozna malinko lepsi. Clovek alespon nemusi pracovat s celou dalsi technologii (kontejnery) jen proto, aby si pustil python. A totiz `pyenv`. Potom pro test noveho pythonu (urcite i na starem mintu) `pyenv install 3.10.6` a je hotovo.
No to evidentne mame. Sada scriptov ktora za mna spravi malu cast prace a ostatok si musim aj tak zriesit sam, je pritaz. Ibaze by som nebol schopny tu pracu spravit sam, potom by to bola neskutocna pomoc. Aj taky LAMP je podla mna pritaz, ale je to tym ze nie som lama a som shopny administracie linuxu, httpd, mysql a php.
Ad lama. Nezufajte, az si uvedomite svoje nedostatky, tak na nich mozete zapracovat. Tiez som mal casy ked som si myslel ze ku mne nie je paru. Mna to preslo s pubertou. Nikto sa nerodi dokonaly, treba sa k tomu prepracovat...
Nejde o to ci je to samostatny balicek ale o izolaciu. Pri vyvoji, testovani a podobne vznika v pracovnom priestore urcite mnozstvo artefaktov. Parkrat som uz pri zistovani priciny hlasky podriadeneho "ale mne to u mna funguje" narazil na to ze ma pod lampom x verzii php, a test pre inu verziu interpretru spusta v adresari kde pted chvilou testoval na dalsej verzii interpretru. Po vycisteni samozrejme "ale mne to..." prestalo platit. Zbytocne zabity cas, nie len jeho ale aj moj.
2. 9. 2022, 17:51 editováno autorem komentáře
https://peps.python.org/pep-0622/#custom-matching-protocol
v pythonu se uvazovalo o uzivatelsky definovatelnem chovani metodou __match__, ale nakonec to zamitli. Pokud by to v budoucnu pridali,bylo by mozne implementovat napriklad
case RegexMatchingGroup(r'My name is (name) .', name):
Jako popravdě mám z toho smíšený pocit. Na jednu stranu je fajne, jak se Python vyvíjí a nepřešlapuje na místě. Na stranu druhou už to není ten snadný jazyk, jak býval někdy okolo Pythonu 2.x nebo i 1.6 (a teď se podržte - viděl jsem tuto verzi používat!). S novými konstrukcemi, možností zápisu datových typů, teď ještě novými operátory (Walrus operátor asi začátečníky dost zmate) a tak...
Vidím to podobně, Python jde cestou C++, "feature creep as a feature". Věta There should be one – and preferably only one – obvious way to do it už dávno neplatí.
30. 8. 2022, 10:07 editováno autorem komentáře
Pohybuji se na rozhraní dvou světů - "velké" IT, tedy firmy, které mají velké IT oddělení a mohly si dovolit migraci už dávno (a někdy to dost bolelo). A potom malé firmy, co mají nějaké aplikace kdysi udělané v Pythonu 2 (různé reporty atd.) a tam prostě nejsou peníze a hlavně vůle s tím něco dělat - jen vždycky někdo něco do skriptu přidá, ale migraci na Python 3 si nelajzne. Takže tam se udržují prastaré Pythony 2.
To samozřejmě chápu, ale Python 2 je legacy jazyk se všemi důsledky. Navíc ta migrace není nijak nezvládnutelná ani v menších firmách, ale chce to rozumně naplánovat a rozfázovat. A mít člověka, který skutečně umí Python a ví, co se mezi v2 a v3 změnilo, ale to se dá víceméně řešit pár hodinami času externisty.
Klicove je nejaky cas udrzovat zpetnou kompatibilitu a testovat pomoci tox na obe verze pythonu.
Prepsat rovnou do idiomatickeho 3, tak ze je to nekompatibilni s 2, je u vetsiho projektu temer nemozne, protoze nemuzete prepisovat po castech bez rozbiti projektu.
30. 8. 2022, 23:15 editováno autorem komentáře
Ja som fortran IV ani fortran 66 nepoznal, ale bol som len donuteny na skole naucit sa fortran 77 a pisat v tom programy (numericka matematika). Potom, po par rokoch, som sa nahodou dostal na forum https://www.tek-tips.com/threadminder.cfm?pid=214 a tam som sa prvy krat stretol s fortranom 90/95. Spociatku som myslel jak hnusny je ten novy fortran oproti klasike 77, ale prechod bol uplne plynuly a bezbolestny. Teraz uz ani nejako neregistrujem ci pisem vo fortrane 77 alebo 90.
Myslíš něco podobného? Někdy se to hodilo :D ... Takovej chudej swich
def update(self, action: Action) -> 'Machine': """ Update the machine state. """ state = { (State.CLOSED, Action.OPEN): State.OPENED, (State.OPENED, Action.CLOSE): State.CLOSED, ... }[(self.state, action)] ...
31. 8. 2022, 16:16 editováno autorem komentáře
Ale to prechazels odjinud. Takovy zacatecnik asi muze byt zmateny. ale popravde nevim, protoze tady se decka (15 a 17 let) sice uci Python, ale nekde na urovni puvodniho Pythonu 1 :-) - tedy zadne list comprehensions, pochopitelne vubec nic s typovou anotaci, zadne f-stringy, bodudik do nich ani necpou OOP
Osobně mi přijde, že nejproblematičtější oblastí je formátování řetězců - teď máme (pokud mi něco neuniká) 4! způsoby jak formátovat řetězec standardními prostředky Pythonu:
1. Klasický C přístup s %
2. Rust-like formátování s .format()
3. f-string
4. Template strings
To je docela přehnané, podobně zbytečná mi přijde i dualita používání jednoduchých a dvojitých uvozovek.
Walrus operator má v zásadě hlavní hodnotu v list comprehensions a generator expressions. Používat se ale nemusí, jak píšeš.
Python má vyše 30 rokov. Je pochopiteľné, že sa autori rozhodli pridať nejaké nové prvky z iných jazykov. Ja to kvitujem. Trebárs ten fstring je jedným z najlepších a najprehľadnejších riešení aké poznám. Tie ostatné sú historickým reliktom; programátori nie sú nutení poznať/používať všetky spôsoby. V C# je to podobne; tam je tých vylepšení na mraky.
Nik nedokáže navrhnúť jazyk hneď perfektne na prvý krát.
Klasický zastaralý C přístup s % doporučuju nepoužívat. F-stringy jsou super na krátké formátované řetězce. Na delší řetězce nebo řetězce, které obsahují hromadu výpočtů, používám pro lepší čitelnost metodu format(). Template strings jsem dosud neznal. Zdá se, že mají úzce zaměřené použití.
V 99 % času používám jednoduché uvozovky. Jen výjimečně použiju dvojité právě v f-stringu: f'Mlíko stojí {mliko["cena"]} Kč'
Tak ziadny jazyk nie je pre lamy, teda ak v nom maju programovat. Programovanie je o mysleni, nie o pouzitom jazyku.
Akoze explicitne pretypujete nieco co netreba? To ale nie je problem s pythonom, nespravne explicitne pretypovanie by robilo neplechu ajv inom jazyku. Ako nie ze by bolo explicitne pretypovanie v niecom na skodu. Oproti implicitnemu pretypovaniu si to takmer kazdy vsimne pri codereview.
> Akoze explicitne pretypujete nieco co netreba?
Ne, prostě například vyklopím slovník pomocí json.dumps(), chci ho poslat pomocí ZeroMQ sock.send_multipart(), a ono to spadne že send_multipart chce bytes ale json.dumps vyrobilo string. Tak tam napíšu json.dumps(foo).encode("ascii") a funguje to. Tak proč se tohle nemohlo udělat samo.
> Tak proč se tohle nemohlo udělat samo.
Pokud by ZeroMQ usoudilo, že by mělo jako argument funkce send_multipart přijímat i stringy, tak jim stačí přidat jeden nebo dva řádky: if isinstance(msg, str): msg.encode()
. A udělalo by se to z pohledu uživatele "samo". To, že tam tuhle fíčuru nepřidali, svědčí o tom, že to nedává smysl.
Bajty jsou fundamentálně něco odlišného než stringy a nejde mezi nimi nerozlišovat. Kdyby například výstup z funkce byl v bajtech, tak pro string musím zase otravně volat result.decode()
. Jako by se to nemohlo udělat samo... Ale co když je výstupem funkce JPEG obrázek? Nebo data videohovoru?
Nedávno som sa hlbšie venoval práve pattern match syntaxe. Podľa mňa nejde len o nejaký vylepšený switch/case, ale o fundamentálne hlbší spôsob analýzy dát.
Práve v poslednej dobe sa pattern match pridal do viacerých jazykov: PHP, Python, Groovy (switch expression), Java či C#. Hodnotenie: Java (bieda), Python, PHP (slabé), Kotlin, C#, Rust, Scala (OK), Groovy, F# (excelentné).
Raku je pravdepodobne tiež veľmi dobré; Clojure tuším zo svojej podstaty pattern match nepotrebuje.
Ináč jednotlivým voľbám sa hovorí arms ako protikladu branches pri klasickom switch/case.
Tie excelentné jazyky majú guards, ranges, a množstvo spôsobov ako rozpitvať dátové štruktúry. Pattern match je výraz, ktorý vracia hodnotu. Podporujú priamy regex match.
def rnd = new Random() def ri = rnd.nextInt(-5, 5) def res = switch (ri) { case { ri < 0 } -> "${ri}: negative value" case { ri == 0 } -> "${ri}: zero" case { ri > 0 } -> "${ri}: positive value" } println res
Tento Groovy príklad ukazuje priradenie voľby do premennej a guards.
def rnd = new Random() def ri = rnd.nextInt(0, 120) switch (ri) { case 1..30 -> println('value is in the range from 1 to 30') case 31..60 -> println('value is in the range from 31 to 60') case 61..90 -> println('value is in the range from 61 to 90') case 91..120 -> println('value is in the range from 91 to 120') }
Groovy a ranges.
def words = ['week', 'bitcoin', 'cloud', 'copper', 'raw', 'war', 'cup', 'water'] def selected = [] for (word in words) { def res = switch (word) { case ~/^w.*/ -> word case ~/^c.*/ -> word default -> 'skip' } if (res != 'skip') { selected.add(res) } } println selected
Groovy a regex výrazy.
open System printf "Enter a number: " let value = Console.ReadLine() let n = match Int32.TryParse value with | true, num -> num | _ -> failwithf "'%s' is not an integer" value let f = function | value when value > 0 -> printfn "positive value" | value when value = 0 -> printfn "zero" | value when value < 0 -> printfn "negative value" f (int value) f n
F# a spracovanie chýb.
let grades = ["A"; "B"; "C"; "D"; "E"; "F"; "FX"] for grade in grades do match grade with | "A" | "B" | "C" | "D" | "E" | "F" -> printfn "%s" "passed" | _ -> printfn "%s" "failed"
F# a viacnásobné voľby, ktoré výrazne skracujú zápis.
Ten pattern matching na třídu bude občas docela peklo, protoze vubec nebere ohled na argumenty metody __init__, jak by se na prvni pohled zdalo.
Specifikace je tady: https://peps.python.org/pep-0634/#class-patterns
class Foo:
def __init__(self, x, y=0, z=0):
self.a = x
self.b = y
self.c = z
match subject:
case Foo() - matchuje pomoci isinstance(x, Foo)
case Foo(a=1, b=2) - navic testuje zda subject.a == 1 a subject.b==2
case Foo(1, a=1, b=2) - Nejprve se zase provede isinstance(x, Foo), pak se pomoci subject.__match_args__ se zjisti jmeno atriburtu pro prvni argument a pak se zkontrolujou hodnoty atributu stejne jako v prechozim pripade. Pro built-in typy (viz vycet v dokumentaci) se to samozrejme chova jinak.
To ale znamena, ze vyraz Foo(x, y=z) uvnitr 'case' znamena (semanticky) neco uplne jineho, nez ve zbytku kodu. Nejsem si jisty, jestli se mi to libi.
Vnorene typy funguji, pokud myslite tohle
class Point: def __init__(self, x, y): self.x = x self.y = y class Line: def __init__(self, a, b): self.a = a self.b = b l = Line(Point(0, 0), Point(1, 1)) match l: case Line(a=Point(x=0, y=0), b=Point(x=x, y=y)): print(x, y) case _: print('no match')
vypise 1, 1
Na to je jednoduché řešení; nepoužívat positional patterns vůbec. Já ve skutečnosti v Pythonu preferuju používat keyword argumenty v Pythonu; pak je rozumná jistota, že posílám hodnoty tam, kam potřebuju a žádná změna signatury funkce/metody to nerozbije. Explicitní je lepší než implicitní a tady na 100%.
> On asi neni problem jen v signature, ten konstruktor muze argumenty ruzne transformovat.
Nejen konstruktor, objekt v Pythonu je obecně mutable a s atributy se může stát kdykoli cokoli. Já jsem, co se týče signatury, ale měl na mysli normální volání funkcí, ne pattern matching.
31. 8. 2022, 19:24 editováno autorem komentáře