Python: jak zjistit volající funkci

Neurolenler

Python: jak zjistit volající funkci
« kdy: 11. 01. 2013, 14:23:27 »
Dobrý den,

měl bych otázku jak nejlépe zjistit jaká funkce si z něčeho vyžádala data?
např.
Mějme třídu, která obsahuje data a ta třída je zároveň iterátor. Zajímalo by mě, jakým způsobem může např. ta třída zjistit, jaká funkce/metoda jí používá jako iterátor a na základě toho třeba rozhodnout, která data z iterátoru by mohla vrátit.

http://docs.python.org/2/library/inspect.html
Našel jsem na webu pythonu modul inspect, který by tuto informaci měl být schopen zjistit, ale nejsem si jistý, jak k tomu přistoupit. Ten modul vypadá na první pohled dost složitě a nejsem si jistý, která informace by pro mě měla být důležitá.

Mým cílem, je mít třídu, která by šla zpracovat přímo v různých funkcích a přitom by automaticky dané funkci předhodila správná data pro zpracování. Případně jak něčeho podobného dosáhnout?
« Poslední změna: 11. 01. 2013, 14:36:38 od Petr Krčmář »


Re:Python: jak zjistit volající funkci
« Odpověď #1 kdy: 11. 01. 2013, 14:46:40 »
Nechci nějak prudit nebo něco, ale podle mě se jedná o principilně špatný návrh a i kdyby to šlo, rozhodně bych to nepoužíval.

Funkce, která pro stejné argumenty vrátí "magicky" v různých případech různá data, to není jenom zlo, to je zlo na desátou :)

tadeas

Re:Python: jak zjistit volající funkci
« Odpověď #2 kdy: 11. 01. 2013, 14:48:12 »
Pokoušíš se o naprosto neskutečnou prasárnu. Ale to je tvoje věc :) .

Koukni na modul traceback, zejména funkci format_stack.

Neurolenler

Re:Python: jak zjistit volající funkci
« Odpověď #3 kdy: 11. 01. 2013, 15:04:55 »
Děkuji za vyjádření, sám vím, že to asi dobrá cesta není..
Pokusím se to ještě blíže upřesnit... Cílem by mělo být něco
třída A figuruje jako zásobník na instance dalších tříd(třída B, hooodně instancí s různými parametry).
Třída A je má urovnávat a vracet dle potřeby pouze ty, které mají určité parametry. Pokud změním nějaký parameter v jedné z instací třídy B, tak by třeba třída A již tuto hodnotu vrátit neměla a měla by jí přeskočit. Bohužel na tento typ zpracování se list, nebo slovník nehodí, takže musím mít vlastní iterátor ve třídě A.

No a tyto parametry se liší pro různé funkce, které je mají zpracovávat. Ano vím, že by bylo ideální si je nejdříve rozkouskovat, aby následně je každá funkce mohla zpracovat samostatně a ty, které je nezajímají nedostala. Problémem je, že během nějaké chvíle se parametry v instancích třídy B mohou upravit a já již následně opět potřebuji ve třídě A vracet jiné.

jinak se na modul traceback podívám, děkuji.

JS

Re:Python: jak zjistit volající funkci
« Odpověď #4 kdy: 11. 01. 2013, 15:11:02 »
Jak uz rikali jini, neni to dobry navrh.

Asi by bylo lepe, nejak explicitne (pomoci nejake pomocne datove struktury) sledovat, s cim ktera s tech trid/funkci manipuluje. Tim by se fakticky ta informace dostala volanym funkcim primo.

Aneb jak pravi jedna ze zasad Pythonu: "Explicit is better than implicit."


Re:Python: jak zjistit volající funkci
« Odpověď #5 kdy: 11. 01. 2013, 15:27:07 »
Podle toho letmého popisu zadání se nejedná o žádné raketové inženýrství.

Prostě když mám kolekci ledniček a konvic, tak vytvořím funkce fridges(), kettles() a all(), které vrací objekty daného typu.

Pokud jsou ty parametry trochu dynamičtější - chci vrátit třeba jenom bílé objekty, aniž bych něco věděl o jejich struktuře, tak se prostě objektu zeptám: o.is_white() - python narozdíl od C++ umožňuje to jednoduše udělat i když o objektu nic nevím. Dokonce můžu i reagovat na to, že objekt tuhle metodu vůbec nemá (pak třeba budu předpokládat, že bílý není). A na základě téhle otázky pak vytvořím metodu white_objects().

A pokud mi ani tohle nestačí, můžu použít obecný test tohodle typu: all_objects_with("method") - který pro každý objekt udělá to samé, co v předchozím odstavci, akorát pro parametrizovanou metodu "method".

Neumím si představit situaci, ve které by sis nevystačil s jednou z těhle 3 věcí...

Vymýšlet nějaké nestandardní konstrukce většinou není dobrý nápad, asi bys udělal líp, kdybys líp popsal situaci a zeptat se na názory, kdo by ji jak řešil. Zkušených programátorů, kteří budou určitě umět dobře poradit, je tady spoustu.

asdfghjkl

Re:Python: jak zjistit volající funkci
« Odpověď #6 kdy: 11. 01. 2013, 15:34:39 »
třída A figuruje jako zásobník na instance dalších tříd(třída B, hooodně instancí s různými parametry).
Třída A je má urovnávat a vracet dle potřeby pouze ty, které mají určité parametry. Pokud změním nějaký parameter v jedné z instací třídy B, tak by třeba třída A již tuto hodnotu vrátit neměla a měla by jí přeskočit. Bohužel na tento typ zpracování se list, nebo slovník nehodí, takže musím mít vlastní iterátor ve třídě A.

No a tyto parametry se liší pro různé funkce, které je mají zpracovávat.

Zapomeňte na jakékoliv detekování toho kdo volá metody iterátoru a podle toho vracení různých výsledků - to je řešení z absolutního dna designové žumpy! Jediná povolená vazba volaného na volajícího jsou předávané parametry při volání (metody, funkce, procedury - to je jedno jak se tomu ve kterém jazyce říká).

Jedno z možných řešení které mi připadá jako správně z pohledu čistoty designu je předat ta výběrová kritéria té metodě třídy A která vrací iterátor, a tato výběrová kritéria zohlednit v té vracené instanci iterátoru.

Další věc je jak efektivně implementovat iterátor nad spoustou měnících se dat (instancí třídy B), ale to už je jiná záležitost.

Neurolenler

Re:Python: jak zjistit volající funkci
« Odpověď #7 kdy: 11. 01. 2013, 18:38:21 »
Vidím, že se to tu rozjelo :)

opět, vím, že se jedná o špatný návrh, ale povím k tomu ještě pár věcí. Není problém abych to rozdělil a měl např. typy třídy B v podobě
[Ba,Bb,Bc,Bd,Bq,Bx ...] já je tímto způsobem i rozdělené mám. Uvnitř třídy A je několik pomocných zásobníků, které je rozdělují třídy B na další verze.

Když ale vidím, ty nápady, tak jsem si uvědomil, že jsem zapomenul zmínit jednu důležitou věc. Já bohužel nemůžu funkce, které zpracovávají ty jednotlivé třídy B upravit. Dále jde o to, že ty funkce jsou primárně určené právě pro již vybrané množství dat. Jenže program pracuje s celkem, který se jako celek předává těm funkcím.
díky tomuto právě nemůžu např. použít metodu objects_ba(), objects_bb(), objects_bc(). Ano byl by to ideální případ, ale není to tak jednoduché.

Napadla mě ještě možnost ... Dovedu postupně dopředu určit, kdy je která funkce volaná..... takže i vím, že když jedna doběhne, já by měla následovat. Možná by cesta, která by nastavovala nějakou globální hodnotu pro třídu B a ta následně věděla, že má vracet jiné hodnoty?
Jenže nevím, jestli to není ještě horší návrh.

Můj původní předpoklad totiž byl, že zjistím jaká funkce, mě volá a následně z vybraného zdroje např. třídy Bb budu vracet tyto instance.

Na druhou stranu děkuji, za názorné vyslovení, že toto není dobrá cesta ;) Pokud někdo máte ještě nějaký nápad, který by šel na straně třídy A  použít, rád si ho poslechnu.

Re:Python: jak zjistit volající funkci
« Odpověď #8 kdy: 11. 01. 2013, 21:14:15 »
Pokud někdo máte ještě nějaký nápad, který by šel na straně třídy A  použít, rád si ho poslechnu.
Já za sebe můžu říct, že z těch střípků, co tady píšeš, moc nechápu, o co má jít. Snad budou ostatní o několik řádů inteligentnější než já a nejenom to pochopí, ale i poradí. Jinak bys holt musel to zadání napsat nějak stručně, jasně a výstižně, ideálně ilustrovt na příkladě a nesoukat to ze sebe jak z chlupaté deky...

Juraj

Re:Python: jak zjistit volající funkci
« Odpověď #9 kdy: 11. 01. 2013, 21:34:38 »
Nedavno som cital dobry clanok o dekoratoroch v pythone: http://www.brianholdefehr.com/decorators-and-functional-python

no a napadlo mi ze by si vratil iterator na zabalene objekty B a az podla toho ako sa tie dekorovane objekty pouziju by si vyberal/volal skutocne B objekty. Zavisi to samozrejme od toho, ci ten volajuci kod sa da rozlisit podla toho ako tie B objekty pouziva ..

Logik

  • *****
  • 995
    • Zobrazit profil
    • E-mail
Re:Python: jak zjistit volající funkci
« Odpověď #10 kdy: 11. 01. 2013, 21:52:48 »
Jestli dobře chápu, je nějakej proces (kterej Ty modifikovat nemůžeš), kterej po Tvojí třídě chce nějaký data.
A ty jsi schopen identifikovat která data buďto dle pořadí volání, nebo podle toho, kdo Tě volá, tu informaci ale nedostáváš.
Pokud tomu opravdu tak je, tak Ti asi opravdu nic jiínýho nezbyde.
Design je to sice otřesnej, ale pokud s rozhraním nemůžeš hýbat...

Kód: [Vybrat]
import inspect
info =  inspect.getargvalues(inspect.currentframe().f_back)

info[3][info[0][0]]

problém Ti ale nastane v okamžiku, kdy Ta třída při tom volání použije např. vnořenou funkci. To bys ještě musel testovat, že první argument je opravdu objekt jedné z chtěných tříd a kdyžtak lízt po stacku nahoru... No, čím víc o tom přemýšlím, pokud víš, v jakém pořadí klient data chce, tak to tam zadrátuj napevno dle pořadí, protože se to stejně jinak 100% dobře napsat nedá a radši to mít "napevno", než heuristikou, která pak může v neočekávaný chvíle selhávat.

Neurolenler

Re:Python: jak zjistit volající funkci
« Odpověď #11 kdy: 12. 01. 2013, 12:16:23 »
Ok děkuji za rady >> trochu jsem to prohlédl..
s modulem traceback, se moc dobře nepracuje ;) Ale jde to z něho přes zmíněnou metodu traceback.format_stack()[0], docela dobře také zjistit.
na konec jsem ale použil odlišnou část a to je právě modul inspect > a jeho stack()

takže výsledné zjištění jména funkce může vypadat asi takto... (na straně třídy A)

import inspect
func_name_data = inspect.stack()[3][4][0].lstrip()
func_name = func_name_data.rsplit("(", 2)[0]

No zatím se zdá, že to funguje. Ještě na to udělám, nějaký fail-safe mechanismus a otestuji testovací scénáře a uvidí se. Možná pro jistotu implementuji i tu verzi, která bude dopředu vědět, která funkce bude následovat (pro porovnání)

Jinak k těm dekorátorům, no já sice zhruba vím k jakým parametrům, ty funkce přistupují a co upravují, ale oni se dost překrývají. A dále tomu moc nerozumím. No zkusím to více prohlédnout.

Jinak stále platí, že se nebráním lepšímu řešení ;)

Logik

  • *****
  • 995
    • Zobrazit profil
    • E-mail
Re:Python: jak zjistit volající funkci
« Odpověď #12 kdy: 12. 01. 2013, 18:24:22 »
Pokud to chceš dělat podle jména funkce, tak je jednodušší tadle cesta:
http://stackoverflow.com/questions/4492559/python-code-to-get-current-function-into-a-variable/4493322#4493322
viz funkce getfunc, první tři řádky
ale doporučoval bych Ti neporovnávat jméno funkce, ale porovnávat samotnej objekt funkce (co když se dvě metody volajících objektů budou menovat stejně??), tzn. použít i ten překlad jména funkce na objekt, jak je ve zbylejch rádcích fce.

PS: Osobně ač dekorátorům rozumím, tak té radě s dekorátory také "nerozumím". Myslím, že její autor
nepochopil buďto dekorátory, nebo Tvůj problém.