Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: dustin 17. 06. 2017, 12:46:50

Název: Python - circular importy v type hintech
Přispěvatel: dustin 17. 06. 2017, 12:46:50
Nedávno tu proběhla debata o pozici pythonu jako kvalitním programovacím jazyku. Mohu tedy poprosit místní gurus o úplně základní radu?

Jsem javista. Doma dělám na soukromém projektu v pythonu, protože už mám nějaký kód z dřívějška a (zatím) se mi to nechce přepisovat do javy. Používám pycharm, python 3.4 v Mintu 18.

Snažím se psát objektově, protože jsem na to zvyklý. Současně mám rád v jednom souboru jednu "public" třídu (může obsahovat i "privátní", které se nepoužívají jinde). Samozřejmě chci používat v maximální míře typehinty, abych se v kódu vyznal a maximálně využil možnosti IDE. Bohužel typehinty vyžadují importy a vedou přímo na zakázané circular importy. Diskuse bez rozumného závěru je např. https://github.com/python/typing/issues/105 , https://stackoverflow.com/questions/39740632/python-type-hinting-without-cyclic-imports .

Doporučuje se:

forward reference jako string - i pro tu chce IDE import statement, aby věděl, kde to najít

import xxxxxx bez from  a v kódu použít celou cestu - mám projekt ve vnořených modulech, abych to měl aspoň trochu rozdělené. Typehinty jsou pak hodně dlouhé - lze to prosím nějak naaliasovat, abych pokaždé nemusel uvádět celou cestu?

I tak mi to nefunguje - příklad:

Modul ui (s __init__.py) -> soubor webui.py -> class WebUI.

Ve stejném adresáři chci ve třídě ui/webapp.py-> class WebApp  v metodě volané zvenku označit typehintem třídu WebUI. Ta ale vytváří instanci třídy WebApp, tudíž samozřejmě má soubor webap.py importovaný.

Zkusím standardní import:

Kód: [Vybrat]
from uis.webui import WebUI
...
def main(self, webui: WebUI):

Klasický circular import vzniklý pouhým typehintováním WebUI, nogo.

Dobře, zkusím variantu pouhého importu

Kód: [Vybrat]
import ui.webui
...
def main(self, webui: uis.webui.WebUI):

Výsledkem je

Kód: [Vybrat]
AttributeError: module 'uis' has no attribute 'webui'
Samozřejmě mohu nic neimportovat, WebUI dát jako string, ignorovat chybu IDE, že daný typ nezná a rezignovat na jakékoliv nabídky proměnných atd. Takový vývoj je mi však silně proti srsti.

Mohu poprosit o zkušenosti, jak v praxi řešíte typehinty a circular importy? Předem díky moc.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 17. 06. 2017, 12:56:17
Oprava příspěvku - ten modul se jmenuje uis (adresář uis), tedy nefunkční import je správně:

Kód: [Vybrat]
import uis.webui
"ui" je jenom překlep na několika místech v needitovatelném příspěvku.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 17. 06. 2017, 13:54:58
Aha, pro tohle je určena podmínka

Kód: [Vybrat]
if TYPE_CHECKING:
  from xxxx import yyyy

https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING

Nic moc, protože to IDE negeneruje samo (narozdíl od importu), tudíž se na to bude zapomínat. Ale budiž, dá se.
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 17. 06. 2017, 14:58:57
Nesvazovat mixiny s konkrétním typem, ale s rozhraním.

https://stackoverflow.com/questions/39740632/python-type-hinting-without-cyclic-imports/39741253#39741253
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 17. 06. 2017, 15:32:58
Interfacy mají také  typehinty, co když bude smyčka v deklaracích svých metod (AInterface má metodu s parametrem typu BInterface a naopak)? Jak to pak vyřeší interfacy místo konkrétních implementací? Ten hack s podmíněným importem jo, do mi dává smysl.
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 17. 06. 2017, 16:41:40
Interfacy mají také  typehinty, co když bude smyčka v deklaracích svých metod (AInterface má metodu s parametrem typu BInterface a naopak)? Jak to pak vyřeší interfacy místo konkrétních implementací? Ten hack s podmíněným importem jo, do mi dává smysl.

V AInterface se volá metoda z BInterface s parametrem AInterface? Pokud ne, tak bych tu metodu dal do jiného interface a odstranil závislost BInterface na AInterface.
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 02. 07. 2017, 01:38:38
Protokoly všechny problémy s importy docela dobře řeší

https://www.python.org/dev/peps/pep-0544/

bude to součástí 3.7., ale můžete to používat už teď.

https://www.python.org/dev/peps/pep-0544/#implementation

Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 08:19:00
Ten text jsem jenom prolétl. Pokud jsem to pochopil, řeší problém s circular importem, pokud by všechny mé třídy měly předpisy protokoly a jako typy bych používal je (protože se údajně nemusí importovat). To mi přijde ještě daleko nepraktičtější, než typehintové importy dát do if TYPE_CHECKING, což funguje OK.
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 02. 07. 2017, 08:35:00
Ten text jsem jenom prolétl. Pokud jsem to pochopil, řeší problém s circular importem, pokud by všechny mé třídy měly předpisy protokoly a jako typy bych používal je (protože se údajně nemusí importovat). To mi přijde ještě daleko nepraktičtější, než typehintové importy dát do if TYPE_CHECKING, což funguje OK.

v místě, kde byste musel jen kvůli typu použít cirkulární import, si místo něho můžete definovat protokol. Asi není třeba to používat všude.



Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 09:08:15
To mohu, ale přece nebudu dodělávat protokoly zpětně u některých víceméně náhodně vybraných tříd (kde zrovna došlo k circular importu). Ty by měly sloužit k něčemu koncepčnímu, ne k zpětnému řešení nedokonalosti ekosystému jazyka (type hinty dolepené později + IDE vyžadující importy, aby se v tom vyznalo). To je větší hack, než stejným pracným a hloupým postupem spustit/chyba/opravit přesunut kolizní importy do type-checking podmínky.
Název: Re:Python - circular importy v type hintech
Přispěvatel: deda 02. 07. 2017, 11:33:39
Nedávno tu proběhla debata o pozici pythonu jako kvalitním programovacím jazyku.

Myslím, že po pár příspěvcích je jasné, že to bylo asi myšleno jen jako vtip. Na skriptíky pro admina je to jazyk velmi dobrý, ale na vývoj to není.
Název: Re:Python - circular importy v type hintech
Přispěvatel: Mantak 02. 07. 2017, 13:26:29
Python není Java tak se tam nesnaž naroubovat něco co používáš v Javě.
Název: Re:Python - circular importy v type hintech
Přispěvatel: hawran diskuse 02. 07. 2017, 14:03:02
...
Myslím, že po pár příspěvcích je jasné, že to bylo asi myšleno jen jako vtip. Na skriptíky pro admina je to jazyk velmi dobrý, ale na vývoj to není.

 ;D  :D  :)
Javamane?
Název: Re:Python - circular importy v type hintech
Přispěvatel: Ondrej 02. 07. 2017, 14:07:28
...
Myslím, že po pár příspěvcích je jasné, že to bylo asi myšleno jen jako vtip. Na skriptíky pro admina je to jazyk velmi dobrý, ale na vývoj to není.

 ;D  :D  :)
Javamane?
nebo lopato...
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 15:43:29
Python není Java tak se tam nesnaž naroubovat něco co používáš v Javě.

Nejde o javu, ale o typy. Nedovedu si představit, jak efektivně vyvíjet projekt už o pár desítkách tříd bez typů. Očividně to pálí spoustu lidí, když v poslední době vzniklo několik na sebe navazujících PEPů, které se to nějakým způsobem snaží řešit.

Jinak se mi python docela líbí, hlavně má pěkné snadno použitelné knihovny pro linux, které ve svém projektu výhodně využiji (udev, alsa, integrace s mpv/mopidy, atd.). Ale je pravda, že kdybych nyní začal od nuly, už bych do něj nešel, ta slabá možnost refaktorizace a dost syrové type hinty v IDE (pycharm) dost zdržují.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 15:56:28
Myslím, že po pár příspěvcích je jasné, že to bylo asi myšleno jen jako vtip. Na skriptíky pro admina je to jazyk velmi dobrý, ale na vývoj to není.

Vidím to tak nějak stejně. Skriptíky se v něm píšou perfektně, není potřeba žádný build systém, mohu krokovat, ladit, paráda. Ale na složitější projekt mi to nejpřijde dostatečně robustní. I když v poslední době se to posouvá (typelib, abc pro abstraktní metody/třídy, atd.), jen to chce ještě pár verzí a jejich dobrou podporu v IDE (i když např. pycharm je v podpoře beta vlastností docela dopředu, stejně jako jeho sestra Idea v javě).
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 02. 07. 2017, 18:33:28
Nejde o javu, ale o typy. Nedovedu si představit, jak efektivně vyvíjet projekt už o pár desítkách tříd bez typů. Očividně to pálí spoustu lidí, když v poslední době vzniklo několik na sebe navazujících PEPů, které se to nějakým způsobem snaží řešit.

Cirkulárním závislostem se lze většinou vyhnout jiným rozvržením kódu. Vůbec není nutné mít každou třídu ve zvláštním souboru. To je omezení Javy.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 18:57:29
Rozdělení tříd do více souborů má spoustu praktických výhod - snáze se hledají, je snazší si otevřít třídy ve více panelech vedle sebe v IDE (mám vždy dva editační panely), soubory jsou krátké a přehledné. Snáze se také v rámci jednoho souboru vyhledává/nahrazuje - je to v rámci jedné třídy. Rovněž commity v GITu jsou přehlednější, protože už z výpisu změněných souborů v diffu vidím, jakých tříd se týkal. IMO je soubor na public třídu užitečný způsob.

V některých souborech mám několik spolu úzce souvisejících tříd, ale jen pokud jsou krátké, většinou jen pomocná DTO. Navíc třídy v jednom souboru musí jít ve správném pořadí, jak jsou postupně definované - i tak musí být typehinty uvedené jako stringy v apostrofech. Když se na to zapomene - opět se to zjistí až při prvním spuštění, IDE nic nezahlásí, protože třídu zná, zatímco interpret ne.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 19:20:53
Ještě jsem zapomněl na zásadní přínos rozdělení do souborů - zatím jsem nepotkal IDE, které by nabízelo commit jednotlivých hunků v souboru, ale vždy jeho všechny změny. Takže granularita commitu přes IDE je soubor. Velice často dochází k tomu, že se smíchají dvě změny, které se ale týkají různých tříd. U malých souborů je v IDE commit snadný. Kdybych měl všechny třídy v jednom souboru (zrovna jednu takovou externí knihovnu používám), bylo by commitování přes interaktivní add -i o dost pracnější (nebo bych musel používat nějaký externí GUI nástroj).
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 02. 07. 2017, 19:32:09
Ještě jsem zapomněl na zásadní přínos rozdělení do souborů - zatím jsem nepotkal IDE, které by nabízelo commit jednotlivých hunků v souboru, ale vždy jeho všechny změny. Takže granularita commitu přes IDE je soubor. Velice často dochází k tomu, že se smíchají dvě změny, které se ale týkají různých tříd. U malých souborů je v IDE commit snadný. Kdybych měl všechny třídy v jednom souboru (zrovna jednu takovou externí knihovnu používám), bylo by commitování přes interaktivní add -i o dost pracnější (nebo bych musel používat nějaký externí GUI nástroj).

emacs+magit to umí.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 19:39:49
To je dobře. Již roky doufám, že IntelliJ hunky do svého portfolia doplní, v jejich IDE by se sakra hodily. Ale i tak je daleko rychlejší vybrat celý soubor, než označovat hunky diffu. Občas to dělám v terminálu, nic moc. A proto zůstanu u hodně souborů s minimální velikostí, než doufat, že jsem na nějaký hunk do commitu nezapomněl.
Název: Re:Python - circular importy v type hintech
Přispěvatel: gll 02. 07. 2017, 19:59:05
To je dobře. Již roky doufám, že IntelliJ hunky do svého portfolia doplní, v jejich IDE by se sakra hodily. Ale i tak je daleko rychlejší vybrat celý soubor, než označovat hunky diffu. Občas to dělám v terminálu, nic moc. A proto zůstanu u hodně souborů s minimální velikostí, než doufat, že jsem na nějaký hunk do commitu nezapomněl.

v PyCharmu už to bude brzy https://youtrack.jetbrains.com/issue/IDEA-63201

tohle by neměl být problém dopsat, kdyby byl git plugin spravován komunitou, tak už by to někdo dávno udělal.
Název: Re:Python - circular importy v type hintech
Přispěvatel: dustin 02. 07. 2017, 20:58:52
Výborně, díky. Mohu jen citovat poslední příspěvek: +1 After 7 years, it is happening!