ugrás a tartalomhoz

isinstance - ne használjam?

H.Z. v2 · 2012. Feb. 20. (H), 13.12
Lehet, hogy a hiányos angolom miatt, de nem teljesen világos amit itt ír a szerző az isinstance használatáról.
Ahogy elnézem, ő többé-kevésbé általánosságban, programnyelvtől függetlenül próbálja megfogalmazni, miért ártalmas(???) az isinstance használata, de van egy szakasz amit nem értek: annak megállapítására, hogy egy paraméterként kapott objektum implementált-e egy szükséges interface-t ("to determine whether an object supports a particular interface "), szerinte alkalmatlan és kerülendő az isinstance használata, ugyanakkor nem látom, hogy adna tippet, hogy mit kellene helyette.

A saját problémám: pythonban készítettem egy fa struktúra leírására használható osztályt. (csak tanulgatok, semmi komoly)
Néhány helyen szeretném ellenőrizni, hogy a paraméterként kapott objektum az általam definiált Node osztályból származik-e, ezzel biztosítva, hogy a szükséges attribútumok és metódusok létezzenek benne.
Ha a fentieket jól értelmezem, e célra nem illik ezt használni. De ha ez így van(így van??), akkor hogyan tudnám ellenőrizni?
 
1

getattr()

dyuri · 2012. Feb. 20. (H), 13.59
Pythonban valoban nincsenek interface-ek, tehat hogy egy objektum implemental-e egy interfacet, azt nem egyertelmu megvizsgalni, viszont azt igen egyszeru, hogy rendelkezik-e egy adott metodussal/attributummal, amire neked adott esetben szukseged van:

>>> getattr(proba, 'valami') # exception
...
AttributeError: 'Proba' object has no attribute 'valami'
>>> getattr(proba, 'valami', False) # igy egy feltetelben konnyebb hasznalni
False
>>> proba.valami = 1
>>> getattr(proba, 'valami', False)
1
2

Ezzel nekem egy bajom van...

H.Z. v2 · 2012. Feb. 20. (H), 14.15
Nevezetesen: ez csak arra biztosíték, hogy a megadott nevű attribútum létezik. Hogy ezen a néven valóban az szerepel-e, amit szeretnék, már nem. Ráadásul valamennyi metódust, attribútumot egyenként le kell kérdezni az ellenőrzéshez.

Viszont a python a többszörös öröklődéssel végeredményben ki tudja váltani azt, amire pl. a java interface szolgál ismereteim szerint (sőt...)
Így az én elképzelésem szerint az isinstance, ha megfelelő osztályra kérdezek rá, akkor jó lenne...

[colorer]
class Node(object):
...
if not isinstance(pnode,Node):
raise TypeError("Hibás param...")
...

class A(OsOsztaly,Node):
...

[/colorer]

De ha jól értem a linkelt oldalt, akkor ez nem igazán ajánlatos, bár én nem látom benne a probléma lehetőségét, ha jól választom ki az isinstance paramétereit.
Kicsit elbizonytalanodtam, hogy valamit nem fogok fel...
3

felesleges

dyuri · 2012. Feb. 20. (H), 14.38
Nekem speciel semmi bajom az isinstance-szel.

De ha valami olyan metodust hivsz, ami nem letezik, az ugyis dob egy AttributeError-t, tehat szinte feleslegesen vizsgaltad meg, valoszinuleg nem direkt kapott a fuggveny rossz parametert, igy - hacsak nem csinalsz a metodushivas elott valami szamitasigenyes dolgot - akkor hibajelzesnek jo ez is.

Es szerintem felesleges vizsgalni, hogy az adott objektum teljes egeszeben megvalositja-e az interface-t, ha csak egy-ket dolgot hasznalsz belole. Ez pythonban elegge bevett dolog, igy vannak "definialva" az iteratorok, descriptorok, es sok minden mas. Ha van az objektumodnak __iter__ metodusa, akkor az egy olyan container, ami tamogatja az iteralast - de ha megsem, es for-ral vegig szeretnel rajta menni, akkor valami hiba keletkezik.
4

Azért kerülendő, mert később

Protezis · 2012. Feb. 21. (K), 09.12
Azért kerülendő, mert később nehézkes a program bővítése. Még pontosabban megsérted vele az LSP-t. Egy magyar nyelvű cikk a témában. Keretrendszer szinten viszont sokszor elengedhetetlen a használata.
5

Egyre kevésbé értem...

H.Z. v2 · 2012. Feb. 21. (K), 11.23
Vagy félreértek valamit.
Azzal, hogy ellenőrzöm: a paraméterként kapott objektum valóban abból az osztályból származik-e, amiből várom, miért teszem nehézkessé a későbbi bővítést? (leszámítva azt az esetet, ha átnevezném az osztályt, ami SZVSZ nem túl egészséges dolog)

Egészen konkrétan a típusellenőrzés "tiltása" az, ami zavar az eredeti cikkben. Hiszen a java jellegű nyelvek ezt már fordításkor megteszik. Akkor ők is megsértik ezeket az elveket?
6

PHP-ben van typehint,

Protezis · 2012. Feb. 21. (K), 12.26
PHP-ben van typehint, természetesen azt érdemes, sőt kell használni. Azonban ha valahol nem tudod ősként kezelni a várt elemet, hanem meg kell vizsgálnod, hogy melyik származtatott osztály példánya, úgy később nagy valószínűséggel egyéb vizsgálatokkal kell kiegészítened ezt a kódrészletet (tele lesz if-fel, mert bejön egy új osztály, stb.). Könnyen káosz lehet a dologból. Az instanceof használata alkalmazás szinten egyértelműen bad small.
7

Az PHP... :)

H.Z. v2 · 2012. Feb. 21. (K), 13.00
OK, így ezt a részt értem - amiért értetlenkedek, az az, hogy az eredeti cikk szerzője Python alapokra hivatkozva írta azt, amit. Pythonban viszont nem tudok ilyen lehetőségről. Ott az egyetlen lehetőségem az instanceof segítségével történő ellenőrzés.
Az egyebek nagy részét nem vitatom, tényleg zűrössé teheti a kódot, de az általam vázolt eset kivételével nem is jutna eszembe használni.
8

A kettő szerintem nem

nova76 · 2012. Feb. 21. (K), 22.17
A kettő szerintem nem ugyanarra való. Most vegyük példaként a symfony event megoldását. Teljesen jó hogy bármilyen objektumot (recordot) mentek, akkor dobok egy eventet, például object.save néven. De nyilván az objektumot is átadom. Mivel bármilyen objektum lehet, nem szűkíthetem le egyetlen típusra. Viszont egy új regisztrációnak mehet egy üdvözlő levél a megadott email címére, de egy új város berögzítésének a városok táblába nem kell levelet küldeni a városnak :-) Ilyenkor kell egy feltétel, ami megvizsgálja hogy egyáltalán akarok-e levelet küldeni. Hogyan kellene ezt ilyen jól csak instanceof nélkül megoldani?
Az eseménykezelőt én jó dolognak tartom, mert project szinten teszi lehetővé a változtatásokat (van aki nem szeretne levelet küldeni az új regisztráltnak sem). Tehát az ötlethez ragaszkodnék, még ha egy jobb megoldásnak esetleg jobban örülnék. :-)
9

feature checking

dyuri · 2012. Feb. 21. (K), 23.50
Pont ilyesmire valo, amit fentebb irtam:

def foo_handler(obj):
  if getattr(obj, 'send_email', False):
    obj.send_email()
Ha tud az objektum levelet kuldeni, akkor kuld, ha nem tud, akkor nem csinal semmit. Persze semmit csinalas helyett dobhat exceptiont is, vagy visszaterhet valami nekunk megfelelo ertekkel. Pythonnal (illetve mas dinamikus nyelveknel, pl. javascriptnel) ez egy surun alkalmazott minta, legalabbis en tobbet lattam/csinaltam ilyet, mint instanceof-fal osztaly vizsgalatot. De attol meg el tudom kepzelni, hogy letezik olyan korulmeny, ahol a legegyszerubb az instanceof hasznalata, azzal azonban egyetertek, hogy ha valaki surun hasznalja, az lehet, hogy mashogy gondolkodik, mint ahogy abban az adott nyelvben szokas.