2015-01-28 13 views
5

Obiekt kodu wygenerowany przez kompilator Python zawiera krotkę stałych użytych w instrukcjach (o nazwie co_consts), a także krotkę zawierającą nazwy (o nazwie co_names).Dlaczego python VM ma co_names zamiast tylko używać co_consts?

Po co dwie różne listy? Czy nie byłoby prostsze użycie po prostu nazwisk co_consts?

+0

Aby sprawdzić, czy mówisz o poprawnym cpythonie? Która wersja? –

+0

@GamesBrainiac: 'co_names' jest używane w cpythonie zarówno 2 jak i 3 oraz w pypy. Nie jestem pewien innych implementacji, ponieważ ich nie używam. – 6502

+0

Nie pamiętam wszystkiego dobrze, ale jestem prawie pewien, że ma to coś wspólnego z marynowaniem. –

Odpowiedz

6

Należy wziąć pod uwagę następującą funkcję.

def f(x): 
    x += n 
    return x * 4 

Tutaj x jest nazwą lokalną, jej wartość może się zmienić. 4 jest stałą. Jego wartość nigdy się nie zmieni. Jednak nadal jest to obiekt i lepiej jest je buforować niż tworzyć nowy obiekt za każdym razem, gdy jest potrzebny. Wreszcie, n jest globalnym odniesieniem. Ciąg "n" jest przechowywany przez funkcję, dzięki czemu można go użyć jako klucza do pobrania n z globalnego kontekstu funkcji.

>>> f.__code__.co_nlocals # just 1 (for x) 
1 
>>> f.__code__.co_consts 
(None, 4) 
>>> f.__code__.co_names 
('n',) 
>>> "n" in f.__globals__ and globals() is f.__globals__ 
True 

Powód oddzielenia nazw i stałych jest dla celów introspekcji. Jedynym prawdziwym powodem do scalenia krotek byłaby wydajność pamięci, ale to tylko zyskałoby jeden obiekt i jeden wskaźnik na funkcję. Rozważ następującą funkcję.

def g(): 
    return "s" * n 

Jeśli krotka zawierająca consts została połączona z nazwiskami krotka zawierająca wtedy (nie VM) nie będzie w stanie powiedzieć, jakie wartości były dostępu do globalnych i które były stałe funkcji.

1

wiem, ta odpowiedź jest jak 11 miesięcy nieaktualne ale z mojego majsterkowania wydaje następujące dzieje

Aby uzyskać dostęp co_names w kodu bajtowego, używa LOAD_GLOBAL (indeks nazw CO) i to popycha odniesienie do pożądane co_names na stosie, na przykład produkty pośrednie

Aby uzyskać dostęp co_consts w kodu binarnego, używa LOAD_CONST (wskaźnik consts cO) i jest wpychany rzeczywista wartość przechowywaną w pożądanych co_consts na stosie, na przykład jej bezpośrednie

i nie jestem pewien, czy ma on bezpośredni wpływ na poziom pythona, ale na poziomie bajtowym jest to profou nd różnica

+0

Oczywiście istnieje duża różnica, ponieważ 'LOAD_CONST' ładuje stałą na stosie, podczas gdy' LOAD_GLOBAL' zamiast niej sprawdza. Jednak globalna ** nazwa ** jest po prostu obiektem 'str' Pythona i mogłaby zostać umieszczona na liście' co_consts' zamiast 'co_names'. Punktem mojego pytania jest "dlaczego używanie dwóch list, gdy wystarczy użycie' co_const', byłoby wystarczające? "... Nie jestem ** nie ** mówiąc, że kod operacji' LOAD_GLOBAL' nie jest potrzebny, ponieważ mamy 'LOAD_CONST' , ale tylko, że te dwie osoby mogły użyć tej samej listy zamiast dwóch list. Wszelkie opcode odnoszące się do ** nazwy ** mogły używać 'op_consts'. – 6502

+0

Nie wiem, z jakiego powodu został zaprojektowany, ale 2 instrukcje przesuwają różne typy danych na stos (wartość w porównaniu z odniesieniem). –

+0

Jeśli łączyłeś zarówno nazwy stałe, jak i nazwy, nadal potrzebujesz instrukcji do VM, niezależnie od tego, czy jest to referencja, czy wartość, czyli 2 instrukcje na ładunek, np. loadconstname, setconstnametype, i to nie jest tak szybkie, jak pojedyncze połączenie, plus jeśli masz idiom (np. ja) z bajt kodem, który jest bezpieczniejszy z VM perspektywiczny –

Powiązane problemy