WebHU - Programozási kérdések és válaszok

Miért viselkedik váratlanul az 'is' operátor aritmetikailag egyenlő kifejezésekkel?

Miután elolvasta ezt és ez, továbbra sem értem a következő viselkedést:

a = 1000
b = 1000
print (a == b)
print (a is b)
print (f"id(a) = {id(a)} \nid(b) = {id(b)}")

Ahogy vártam, megkapom

True
True
id(a) = 2806705928816 
id(b) = 2806705928816

De amikor valami ilyesmit próbálok csinálni:

a = 1000
b = 1000 + a - a
print (a == b)
print (a is b)
print (f"id(a) = {id(a)} \nid(b) = {id(b)}")

False kaptam a a is b kifejezésben

True
False
id(a) = 3030783801968 
id(b) = 3030783802064

Miért viselkedik másképp egy változó, amikor egy kifejezés eredményét egész számhoz rendeli, és egy kifejezést más változókkal? Bár matematikailag ez ugyanazt az egész számot adja.


  • Mert a két 1000 literál. Ezeket a program elején határozzák meg. Csak egy kell belőlük. 22.02.2021
  • A második esetben ezek nem ugyanazok az egész számok; ezek különböző egész objektumok azonos értékkel. 22.02.2021
  • mi a váratlan pontosan? Miért elvárja a is b, hogy itt igaz legyen? Az a tény, hogy ez igaz az első példádban, meglepő 22.02.2021
  • Ne használja az is-t az aritmetikai egyenlőség ellenőrzésére, erre szolgál a ==. A is annak ellenőrzésére szolgál, hogy két változó/név ugyanarra az objektumra hivatkozik-e. 22.02.2021
  • Ez totális spekuláció, de az a sejtésem, hogy csak az a kérdés, mennyire okos a fordítóoptimalizálás. Legtöbbször nem törődik azzal, hogy a Python hogyan foglalja le a változó memóriát a motorháztető alatt, de az első esetben egy kis varázslatot csinál, hogy helyet takarítson meg azáltal, hogy elkerüli a duplikált kiosztásokat, amelyek átláthatóak az Ön számára, ha nem. figyeli a id() értékeket. De a második esetben ez nem elég okos, így végül 2 kiosztást kap. 22.02.2021

Válaszok:


1

Amikor valami ilyesmit csinálsz:

(1. eset)

a = 1000
b = a

vagy (2. eset)

a = 1000
b = 1000

A Python elég okos ahhoz, hogy előre tudja, még a végrehajtás után sem lesz szüksége új memóriára.

Tehát a python közvetlenül a végrehajtás előtt az első esetben a b a aliast teszi.

A második eset kicsit más. A Python egy valódi objektum orientált nyelv, a literális 1000 objektumként kezelendő. (Intuitív módon 1000-nek tekintheti egy const objektum nevét).

Tehát a második esetben a a és a b technikailag alias lesz a 1000-ből.

Most a példádban:

a = 1000
b = 1000 + a - a
print (a == b)
print (a is b)

a b hozzárendelése közben a python nem tudja előre, hogy mi lesz a a értéke. Amikor azt mondom, előre, azt értem, mielőtt bármilyen számítási formát elkezdtek volna. Tehát a python lefoglal egy új memóriahelyet a b számára, majd elmenti a művelet kimenetét erre az új memóriahelyre.

Ezt is érdemes megjegyezni:

4-1 is 3
True

Ebben az esetben a python nem menti el ezt a sort a 4-1-el, hanem a fordítás előtt 3-ra dolgozza fel a futásidejű optimalizálás érdekében.

22.02.2021

2

Már van néhány pontos válaszod. Itt adok egy vissza az alapokhoz választ.


Mi az a ==?

A Python == azt jelenti, hogy a bal oldali érték megegyezik a jobb oldali értékkel.

sum([5, 7]) == (48 * 3)**0.5

a True. Több kiértékelési lépés szükséges ahhoz, hogy minden kifejezés elérje az 12 értéket. Még ekkor is az egész szám 12 összehasonlításra kerül a lebegő 12.0 értékkel, ezért az egész számot lebegőponttá kell véglegesen átalakítani.

A lényeg: minden kifejezést a rendszer kiértékel, és az eredményül kapott értékeket összehasonlítja. Ha egyenlőek, akkor a kifejezés igaz.

Mi az a is?

A Python is viszont azt jelenti, hogy a bal oldali név ugyanarra az objektumra mutat, mint a jobb oldali név.

a = 3.14159
b = a
a is b

a True. a hozzá lett rendelve a 3.14159 értékhez. De ami még ennél is fontosabb, van egy memóriablokk, amely egy objektumot tartalmaz, ami jelen esetben a float 3.14159. a az adott objektumra/memóriablokkra mutat. A b a a-ra mutat, ami azt jelenti, hogy ugyanarra a memóriablokkra mutat.


Ezt nagyon egyszerűen tesztelheti: hozzon létre két nevet, amelyek egyszerűen egy számra mutatnak, és hasonlítsa össze őket a is használatával, és nem fognak egyezni:

>>> a = 1239481203948
>>> b = 1239481203948
>>> a is b
False

Ez hamis, mert most két különböző helyünk van a memóriában/objektumban, amelyek mindegyikre mutatnak:

>>> id(a)
140402381635344
>>> id(b)
140402391174416

(A gépén egy másik ids készletet kap. )

Tehát valójában teret vesztegettél, mert két objektum ugyanazon információ számára foglal helyet.

De várj, van még

Ha egyedül játszol ezzel, tonna kivételt találsz az általam leírtak alól, és összezavarod magad. Íme néhány:

>>> a = 157
>>> b = 157
>>> a is b
True

Mit?? Miért igaz ez? A Python optimalizálása érdekében a leggyakoribb számokat optimalizáltuk. Lehet, hogy tévedek, de emlékszem, hogy a memóriában van kijelölt hely a leggyakoribb számok számára. És ezek az első néhány száz egész szám, és néhány másik.

De vannak más optimalizációk is:

>>> a = None
>>> b = None
>>> a is b
True

>>> a = True
>>> b = True
>>> a is b
True

Ezek mind továbbra is ugyanazt a szabályt követik, mint korábban kifejtettem: az oka annak, hogy a is kiértékelődik True-re, mert a a és a b is ugyanarra a helyre mutat a memóriában/objektumban.

Ez ezekben a furcsa esetekben történik a Pythonban végzett optimalizálás miatt. De általánosságban elmondható, hogy az egyetlen módja annak biztosítására, hogy a is kiértékelése True-ra legyen, az az, ha egy név van hozzárendelve egy objektumhoz, amelynek már van neve, például amikor azt írtuk:

>>> a = 3.14159
>>> b = a
>>> a is b
True

írás helyett

>>> a = 3.14159
>>> b = 3.14159
>>> a is b
False
22.02.2021

3

a különbség a helyre való hivatkozásban van. Az '==' ellenőrzi az egyenlőséget az adattípus és az érték tekintetében, azonban az 'is; hivatkozik a változó helyére a memóriában.

is hamis értéket ad vissza az alábbihoz

id(a) = 3030783801968 <----
id(b) = 3030783802064 <----

az alábbiakra igaz lesz

    id(a) = 2806705928816 <----
    id(b) = 2806705928816 <----
22.02.2021
  • Lehet, hogy össze vagyok zavarodva, de úgy gondolom, hogy a kérdés az == és a is közötti különbség helyes megértésével történik. A kérdés az, hogy a Python miért osztja ki az egyik esetben ugyanazt az azonosítót/címet, a másikban miért nem. 22.02.2021
  • a második esetben "a-a" hozzáadásával "további aritmetikát" készített, így a python egy másik helyen tárolja az értéket 22.02.2021

  • 4

    A Python úgy hajt végre egy utasítást, hogy a kifejezéseit egyenként értékeli ki értékekre, majd végrehajt valamilyen műveletet azokon az értékeken.

    Forrás: https://courses.cs.washington.edu/courses/cse140/13wi/eval_rules.pdf

    Alapvetően b = 1000 + a - a nem egy menetben történik meg, hanem több kiértékelésben, és a python minden egyes kiértékelésnél más memóriahelyen tárolja a b eredményét, mint a. Ezen a ponton a és b különböző objektumok.

    az egyenlőség ellenőrzéséhez használja az ==-t.

    annak ellenőrzésére szolgál, hogy az objektumok azonosak-e (a változók ugyanarra a memóriahelyre hivatkoznak).

    22.02.2021
    Új anyagok

    A rádiógomb ellenőrzött eseményének használata a jQueryben
    Ebben a cikkben látni fogjuk, hogyan kell dolgozni a jquery választógombbal ellenőrzött eseményeivel. A választógombok HTML gombok, amelyek segítenek kiválasztani egyetlen értéket egy csoportból...

    Körkörös függőségek megoldása terraformban adatforrásokkal – lépésről lépésre
    Mi az a körkörös függőségek Dolgozzunk egy egyszerű eseten, amikor az SQS-sor és az S3-vödör közötti körkörös függőség problémája van egy egymástól függő címkeérték miatt. provider..

    Miért érdemes elkezdeni a kódolást 2023-ban?
    01100011 01101111 01100100 01100101 — beep boop beep boop Világunk folyamatosan fejlődik a technológia körül, és naponta fejlesztenek új technológiákat a valós problémák megoldására. Amint..

    🎙 Random Noise #2  – Örökbefogadás és hit
    az analitika íratlan világának gondozása Szeretné, hogy ezek a frissítések a postaládájába kerüljenek? Iratkozzon fel itt . "Ha önvezető autókat gyártanak, akkor mi miért ne..

    A legrosszabb politika és prediktív modellek májátültetésre jelöltek számára az Egyesült Államokban
    A máj (vagy óangolul lifer) az emberi test legnehezebb belső szervére utal, amely csendesen működik a nap 24 órájában. Mit csinál a máj? 500 feladatot hajt végre a szervezet egészségének..

    5 webhely, amely 2022-ben fejleszti front-end fejlesztői készségeit
    Frontendmentor.io A tényleges projektek létrehozásával a Frontendmentor.io segítséget nyújt a front-end kódolási képességeinek fejlesztésében. A kódolást azután kezdheti meg, hogy..

    Mikor kell használni a Type-t az interfészhez képest a TypeScriptben?
    A TypeScript a JavaScript gépelt szuperkészlete, amely statikus gépelést ad a nyelvhez. Ez megkönnyíti a robusztus és karbantartható kód írását azáltal, hogy a hibákat a fordítási időben..