Kezdőoldal » Számítástechnika » Programozás » Miért nem hívódik meg a...

Ozmium42 kérdése:

Miért nem hívódik meg a __getattr__ metódus (python3.6)?

Figyelt kérdés

Tegyük fel, hogy van egy osztály:


>>> class MyClass:

... var = 42

... def __getattrib__(self, name):

... print(name)


Ezt példányosítom:


>>> mc = MyClass()


És ebben az esetben:


>>> mc.whatever

whatever


Mivel whatever nevű attribútum első körben nem található, ezért meghívódik a __getattr__ metódus, ami simán csak kiírja az attribútum nevét.


Amit nem értek, hogy ez példányosítás nélkül nem működik, pedig a dir(MyClass) kilistázza a __getattrib__ függvényt, és ha így használom:


>>> MyClass.__getattrib__(MyClass, "whatever")


Akkor működik, viszont ha azt írom, hogy:


>>> MyClass.whatever


Akkor nem, AttributeError-t dob, mintha nem is lenne megírva a __getattr__ metódus.


Lehet valamit tenni, hogy ilyen módon is működjön?



2020. ápr. 1. 22:09
 1/6 anonim ***** válasza:
100%
Nem __getattrib__ hanem __getattr__ kell.
2020. ápr. 5. 13:23
Hasznos számodra ez a válasz?
 2/6 anonim ***** válasza:
76%
2020. ápr. 5. 13:59
Hasznos számodra ez a válasz?
 3/6 A kérdező kommentje:
Ez elírás, csak a leírásban rontottam el. A __getattr__ metódusról van szó.
2020. ápr. 5. 21:06
 4/6 anonim ***** válasza:
100%

Úgy mellesleg _ jellel kezdődő objektum referenciát "nem illik" közvetlen használni csak belső használat esetében. Persze a lehetőséget nem vették el, mondván hogy úgy használd, hogy tudod mit csinálsz.

Magyarázatok:

Nem kitérő válasz csak egy összefoglalás a teljesség igénye nélkül, hogy mi történik.

def __getattrib__(self, name) esetében a self az a hívás közben önmagára mutató referencia, kötelező paraméter bármelyik metódusnál kötelező. A változó neve igazából nem lenne kötelező hogy self legyen, ez csak konvenció.

Nem használtad semmire ezt a referenciát, csak az utána lévő name paramétert. Ezért igazából a MyClass.__getattr__(MyClass,"whatever") helyett lehetne

MyClass.__getattr__(0,"whatever") is.


Lekérdezhetjük hogy milyen típusú maga a __getattr__ példányosításkor meg a nélkül.

type(MyClass.__getattr__) function lesz, hoppá.

type(mc.__getattr__) pedig method lesz.

Ha példányosítás nélkül hívod akkor sima függvények lesznek melyek def valami(self ...) -ként szerepelnek a class-odba. Példányosításkor van az a feature a python-ba hogy akkor is dinamikusan képes visszaadni valamit ha nincs is olyan adattagja vagy metódusa.

Sőt maguk a metódusok is alapból is dinamikusan generált objektumok( az osztályhoz tartozó példányosítás nélküli függvény megfelelőjük alapján).

Például legyen egy Foo osztályunk:

>>>class Foo:

...def f(self,a):

......self.a = a

Példányosítjuk:

foo = Foo()

foo.a

AttributeError: 'Foo' object has no attribute 'a' kivételt dob, nem meglepő módon.

foo.f hívható így is, ekkor kapunk egy method objektumot.

Ezt akár ki is menthetjük változóba pl. x = foo.f.

Ezen az x változón keresztül is használhatjuk pl. x(10)

Ekkor foo.a -ra kifogja adni a 10-et, mintha foo.f(10)-et hívtuk volna meg. Össze is hasonlíthatjuk hogy foo.f == x True lesz. foo.f == foo.f is True. Azt jelenti hogy ugyanazt az értéket veszi fel, de ha azt nézzük meg hogy ugyanarra az objektumra mutat e foo.f is x False , sőt foo.f is foo.f False mert dinamikusan mindig új method objektum keletkezik, de ugyanakkor amit kimentettünk x-et x is x True lesz vagyis nem csak egyenlő hanem pontosan ugyanaz a method objektum lesz.

Itt is igaz lesz hogy type(foo.f) vagy type(x) method type(Foo.f) pedig function. Vagyis ha történik egy metódus hívás foo.f(10) akkor keletkezik egy új method típusú objektum a Foo osztály alapján mely meg lesz hívva a 10 paraméterrel mely csinál valamit.

Vagyis oszály példányosítással kapott objektum esetében annak minden egyes metódus hívássakkor dinamikusan keletkeznek maguk a metódusok, ha nem létező metódus vagy adattag név lesz akkor még van lehetőség ilyen callback __getattr__ hívásra mely még így is visszaadhat valamit.


Menjünk tovább, az osztályok is objektumok pythonba.

csináljunk egy sima függvényt

>>>def a(b):

...b.a = b.a + 1

Foo.g = a

Hívjuk meg foo.g()

Nézd meg, hogy mit ad vissza foo.a-ra és miért! Mi történt?

2020. ápr. 6. 00:18
Hasznos számodra ez a válasz?
 5/6 A kérdező kommentje:

Nem vagyok benne biztos, hogy az utolsó példával mire akarsz rávezetni.


A leírtak alapján a(b) függvény nem változik, amíg Foo.g-ként hivatkozunk rá. foo.g()-ként viszont azért működik paraméter nélkül, mert itt már példányosítás után methodként viselkedik, és a foo.g() megfelel a g(foo) hívásnak. foo.a értéke nő eggyel.

2020. máj. 1. 18:44
 6/6 anonim ***** válasza:
g(foo) hívásra NameError exception-t fog dobni. Amúgy oké a többi észrevétel.
2020. máj. 1. 23:08
Hasznos számodra ez a válasz?

Kapcsolódó kérdések:




Minden jog fenntartva © 2024, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu

A weboldalon megjelenő anyagok nem minősülnek szerkesztői tartalomnak, előzetes ellenőrzésen nem esnek át, az üzemeltető véleményét nem tükrözik.
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!