2.33. Introspekcja¶
Garść funkcji wbudowanych pozwala działającemu programowi badać samego siebie – wartości, na których pracuje, przestrzenie nazw, w których te wartości żyją, oraz relacje między klasami. Sięgaj po nie, gdy musisz podejmować decyzje na podstawie tego, czym obiekt naprawdę jest, a nie tego, za co podaje go jego wywołujący.
2.33.1. Tożsamość i haszowanie¶
id()– unikalna liczba całkowita, która identyfikuje obiekt tak długo, jak długo on istnieje. Dwie nazwy wiążące ten sam obiekt zwracają to samo id; dwa równe, ale odrębne obiekty – nie.
>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b) # same list
True
>>> id(a) == id(c) # equal but distinct
False
id nie jest przenośne między uruchomieniami i nie ma znaczenia poza odpowiedzią na pytanie „ten sam obiekt czy inny obiekt”.
hash()– wartość skrótu obiektu, ta sama liczba, którejdictisetużywają do jego wyszukiwania. Dwa równe obiekty haszują się do tej samej wartości; w ogóle działają tylko typy haszowalne (przeważnie wartości niezmienne).
>>> hash("abc") # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'
2.33.2. Sprawdzanie typów i wywoływalności¶
type()– dokładna klasa wartości.type(x) is intpyta „czy x jest dokładnie typem int” (bez podklas);isinstance()jest zwykle tym, czego naprawdę chcesz.isinstance()– „czy x jest instancją tej klasy lub jej podklasy?” Standardowe narzędzie do rozgałęziania działania na podstawie typu wewnątrz funkcji.issubclass()– odpowiednik na poziomie klas. Przyjmuje dwie klasy zamiast instancji.callable()–True, jeśli argument można wywołać za pomocą(). Przydatne, gdy otrzymujesz argument, który może być funkcją albo zwykłą wartością.
>>> isinstance(3, int)
True
>>> isinstance(True, int) # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False
Wzorzec wykorzystujący callable:
def call_or_return(x):
return x() if callable(x) else x
2.33.3. Przyglądanie się zakresom¶
globals()– globalna przestrzeń nazw modułu jakodict. Odczyt z niej działa; zapis do niej jest realny, ale robienie tego poza eksploracją w REPL utrudnia śledzenie programu.locals()– lokalna przestrzeń nazw w miejscu wywołania. Wewnątrz funkcji odzwierciedla zmienne lokalne; modyfikowanie zwróconego słownika nie gwarantuje zapisu z powrotem do rzeczywistych zmiennych lokalnych (zachowanie zależne od implementacji).
name = "OpenMV"
def f():
x = 10
print(globals()["name"]) # OpenMV
print(locals()) # {'x': 10}
Te dwie funkcje są przydatne do debugowania oraz dla narzędzi, które muszą odkryć, co zostało zdefiniowane. Sięgaj po nie oszczędnie w zwykłym kodzie – funkcja, która modyfikuje globals(), jest jedną z najtrudniejszych do zrozumienia rzeczy w Pythonie.
2.33.4. Zobacz także¶
dir() i help(), omówione w debugging, to codzienne narzędzia introspekcji do badania powierzchni nieznanego obiektu.