6.7. Pohledy a kopie

Pohled je druhé okno do téhož datového bloku jako zdroj. Žádná data se nekopírují; pohled drží nový deskriptor (vlastní tvar, kroky a dtype), ale sdílí buffer. Pohledy jsou v podstatě zdarma.

Kopie si od kamery vyžádá nový buffer a projde zdroj, aby jej naplnila. Kopie stojí jak čas, tak RAM.

Většina metod měnících tvar vytváří pohledy. Většina metod transformujících data vytváří kopie. Znalost toho, co je co, rozhoduje o tom, zda horká smyčka vyčerpá RAM kamery.

6.7.1. Reshape

reshape() vrací pole požadovaného tvaru. Celkový počet prvků musí zůstat nezměněn, jinak je vyvolána výjimka ValueError

a = np.arange(12, dtype=np.uint8)
m = a.reshape((3, 4))

Výsledkem je pohled – m a a sdílejí data. Zápis přes m[0, 0] = 99 změní i a[0].

Přiřazení nové n-tice do shape je zkratkou pro tutéž operaci:

a = np.arange(9)
a.shape = (3, 3)

6.7.2. Transpose

transpose() (nebo zkratka .T) obrátí osy. Implementováno obrácením kroků – žádná data se nepřesouvají:

m = np.arange(6, dtype=np.uint8).reshape((2, 3))
t = m.T                  # shape (3, 2), shares m's buffer

Transponovaný pohled neprochází datový blok souvisle. Čtení t výše po řádcích navštěvuje pozice v paměti 0, 3, 1, 4, 2, 5, nikoli podkladové pořadí 0, 1, 2, 3, 4, 5, v němž jsou bajty rozloženy. Obyčejná aritmetika a redukce si s tím poradí – procházejí podle kroků – ale tobytes() nikoli, protože vrací podkladový buffer přímo bez kopírování. Bajty, které buffer drží, neodpovídají pořadí, jež naznačuje tvar pohledu, takže metoda vyvolá výjimku ValueError u jakéhokoli nesouvislého pohledu. Pokud jsou bajty potřeba v transponovaném pořadí, nejprve si vynuťte novou souvislou kopii:

bytes_out = t.copy().tobytes()

6.7.3. Flatten a flat

flatten() vrací 1-D kopii pole:

f = m.flatten()          # new dense 1-D ndarray

Předejte order='C' (výchozí) pro procházení poslední osy jako první nebo order='F' pro procházení první osy jako první:

m = np.arange(6, dtype=np.uint8).reshape((2, 3))
# m = [[0, 1, 2],
#      [3, 4, 5]]
m.flatten()              # array([0, 1, 2, 3, 4, 5], dtype=uint8)
m.flatten(order='F')     # array([0, 3, 1, 4, 2, 5], dtype=uint8)

flat je iterátorová forma. Vydává každý prvek ndarray libovolné úrovně jako skaláry, bez alokace ploché kopie:

for x in m.flat:
    print(x)

Pokud aplikace potřebuje projít každý prvek, upřednostněte flat; pokud potřebuje hustý 1-D buffer k předání jiné funkci, použijte flatten().

6.7.4. Iterace

Iterace 1-D pole vydává skaláry; iterace pole vyšší úrovně vydává (n-1)-D pohledy:

m = np.array([[0, 1, 2], [3, 4, 5]], dtype=np.uint8)
for row in m:
    print(row)               # array([0, 1, 2]), array([3, 4, 5])

Řádky vydávané iterací matice jsou pohledy, takže jejich úpravou se upraví zdroj.

6.7.5. Kopie

copy() je explicitní způsob, jak získat nezávislý ndarray, jehož úpravy neovlivní originál. Alokuje se nový buffer a zdroj se do něj projde:

c = a.copy()

tobytes() vrací bytearray, který sdílí paměť s datovým blokem pole. Zápisy přes bytearray upravují pole na místě. Vyvolá výjimku ValueError, pokud pole není husté (řezový pohled, transpozice, …).

tolist() vrací obsah jako případně vnořený Python objekt list. Užitečné pro serializaci malých výsledků; nákladné pro velké, protože každý prvek se stane samostatným Python objektem.

6.7.6. Které operace vracejí co

Úplné pravidlo:

Následující operace vracejí pohledy:

  • slicing – a[1:5], a[::2], m[:, 0];

  • indexování jediné osy u pole vyšší úrovně – m[0];

  • iterace n-D pole;

  • reshape(), když je požadované rozložení kompatibilní;

  • transpose() / .T;

  • frombuffer();

  • asarray(), když dtype odpovídá.

Následující operace vracejí kopie:

Sáhněte po explicitní kopii pouze tehdy, když je skutečně potřeba nezávislý buffer. Na kameře s omezenou RAM je rozdíl mezi pohledem a kopií často rozdílem mezi kódem, který se vejde, a kódem, který nikoli.