6.2. Az ndarray¶
Az ndarray az a típus, amely a numerikus adatokat tárolja a numpy-ban. Két dolog egyben: egyetlen összepakolt adatblokk, és egy kis leíró a blokk előtt, amely megmondja, hogyan kell olvasni.
6.2.1. A doboz belsejében¶
Az adatblokk a tömb minden elemét egymás után tárolja, közöttük semmi pluszzal. Minden elem ugyanannyi bájtot foglal el – egyet egy uint8 értékekből álló tömbnél, kettőt uint16-nál, négyet float-nál. Egy 256 elemű uint8 tömb pontosan 256 bájtnyi adat; ugyanaz a 256 szám egy Python list-ben egy kilobájtot foglal – elemenként egy 32 bites helyet, függetlenül attól, hogy az értéknek ténylegesen mennyire kevés bitre van szüksége.
A leíró rögzíti, hogy mit jelent a blokk. Öt érték elegendő bármely téglalap alakú tömb leírásához, akárhány dimenziós is:
dtype– az elemtípus. Eldönti, hogy hány bájtot foglal el minden elem, és milyen értéktartományt tud tárolni (a Dtype-ok oldalon tárgyaljuk).itemsize– egy elem bájtszélessége, a dtype-ból származtatva.ndim– a dimenziók száma (1 egy vektornál, 2 egy mátrixnál, 3 egy térfogatnál, legfeljebb 4).shape– a méret minden dimenzió mentén tuple-ként.strides– hogyan lépkedj végig az adatblokkon minden tengely bejárásához. A Alak és lépésközök oldalon tárgyaljuk.
Ennyi. A numpy minden gyors útvonala – aritmetika, redukciók, broadcasting, szeletelés – közvetlenül ebből az öt értékből plusz az adatmutatóból dolgozik, elemenkénti Python-többletköltség nélkül.
6.2.2. Mit nyer a tervezés¶
Három tulajdonság következik az „összepakolt blokk + kis leíró” elvből, és ezek határozzák meg a fejezet hátralévő részének viselkedését.
Az elemenkénti matematika egyetlen hívásként fut. Két egyező alakú tömb közötti a + b összeadja a két puffert és egy harmadikba ír, mindezt egyetlen könyvtárhíváson belül. Az np.sin(a) ugyanezt teszi minden elem szinuszára. Az aritmetikai, összehasonlító és bitenkénti operátorok mind így működnek.
Ugyanazon adat más szempontú megtekintése ingyenes. Egy tömb egy alterületének kérése, vagy ugyanazon adat más alak alatti elrendezése, egyetlen bájtot sem mozgat. A művelet egy új leírót ad vissza, amely ugyanarra az adatblokkra mutat. Az eredményt nézetnek (view) hívjuk – egy második ablak ugyanarra az alaptelepülésű pufferre. Egy nézeten keresztüli írás a forrásba ír.
A vegyes alakok is működnek. Egy rövidebb tömb egy hosszabb mellett, egy sor egy mátrix mellett, egy oszlop egy sor mellett – a numpy broadcasting révén igazítja össze őket, ami szabályok kis halmaza, amelyek eldöntik, melyik rövid tengely nyúlik meg, hogy illeszkedjen a hosszúhoz. A nyújtás virtuális; semmilyen adat nem duplikálódik.
6.2.3. Mibe kerül a tervezés¶
Ugyanabból a tervezésből két korlátozás következik.
Minden elem azonos típusú. Egy lista tárolhat egy int-et egy str mellett, egy másik három int értékből álló lista mellett; egy ndarray nem. A dtype a létrehozáskor rögzül. A Dtype-ok oldal tárgyalja a típusok kis halmazát, amelyet a numpy támogat, és az egy típus rögzítéséből fakadó szabályokat.
Egy tömb növelése nem ingyenes. Egy lista tartalék helyeket tart fenn a végén, és olcsón támogatja a .append-et. Egy ndarray pontosan akkora, amekkorának lennie kell; a hozzáfűzés azt jelentené, hogy egy új, nagyobb puffert kell lefoglalni, és a régi tartalmat bele kell másolni. Szándékosan nincs append() metódus. A kamerán a helyes minta az, hogy a célt előre lefoglalod a végső méretén, és feltöltöd azt; a Teljesítmény tárgyalja a technikát.
Az adatokhoz egy összepakolt, típusos pufferrel, a metaadatokhoz egy kis leíróval, és három viselkedési garanciával (gyors elemenkénti matematika, ugyanazon adat másolásmentes alternatív nézetei, és broadcastolható alakok), az ndarray az az alap, amelyre a fejezet többi része épül. Hogy egy tömb valójában hogyan jön létre – egy literálból, egy előre kitöltött lefoglalásból, egy perifériapufferből – a következő gyakorlati kérdés.