Die Python-Funktion object() erzeugt eine minimale Instanz von object — der Wurzel-Klasse aller Python-Klassen. Jede Klasse erbt direkt oder indirekt von object und bekommt damit Default-Methoden wie __init__, __repr__, __eq__, __hash__, __getattribute__. object() selbst hat keine Attribute und wird hauptsächlich als Sentinel-Wert verwendet.
Einleitung
Seit Python 3 ist object die universelle Basis. class Foo: ist äquivalent zu class Foo(object): — alle Klassen sind „new-style". Das bringt jeder Klasse automatisch eine Reihe von Default-Methoden:
__init__(no-op)__repr__→<__main__.MyClass object at 0x...>__eq__→is-Vergleich__hash__→id-basiert__getattribute__,__setattr__,__delattr____dir__,__sizeof__
object() ohne Argumente liefert eine ganz minimale Instanz. Hauptsächlich nützlich als Sentinel — ein eindeutiger Wert, der nirgends sonst vorkommen kann (anders als None, das gültiger Wert sein kann).
Syntax
object()Rückgabewert
Eine neue, leere object-Instanz.
Beispiele
object als Wurzel
Alle Klassen erben von object — die MRO endet immer dort:
class A: pass
class B(A): pass
print(object in B.__mro__)
print([cls.__name__ for cls in B.__mro__])True
['B', 'A', 'object']Default-Methoden inspizieren
Eine ganz neue Klasse hat schon einen Haufen geerbter Methoden — aus object:
class Empty: pass
methods = [m for m in dir(Empty) if not m.startswith("_")]
print(methods) # leer
dunder = [m for m in dir(Empty) if m.startswith("__")]
print(len(dunder), "dunder methods inherited from object")[]
25 dunder methods inherited from objectSentinel-Wert
Ein häufiger Einsatz: ein eindeutiger Marker, der von None unterscheidbar sein muss:
MISSING = object()
def get(d, key):
value = d.get(key, MISSING)
if value is MISSING:
return "Schlüssel fehlt komplett"
if value is None:
return "Wert ist None (aber Schlüssel existiert)"
return value
print(get({"a": 1, "b": None}, "a"))
print(get({"a": 1, "b": None}, "b"))
print(get({"a": 1, "b": None}, "c"))1
Wert ist None (aber Schlüssel existiert)
Schlüssel fehlt komplettPraktische Beispiele
Default-Argument-Sentinel
Mutable Defaults sind eine Falle — ein object()-Sentinel löst das sauber:
_MISSING = object()
def append_item(item, container=_MISSING):
if container is _MISSING:
container = []
container.append(item)
return container
a = append_item(1)
b = append_item(2)
print(a, b) # zwei separate Listen — kein Mutable-Default-Bug[1] [2]Marker für „keine Argument-Übergabe"
Wenn None ein gültiger Wert ist, hilft object() als „nicht übergeben"-Marker:
_UNSET = object()
def update(name=_UNSET, value=_UNSET):
if name is _UNSET:
print("name nicht übergeben")
if value is _UNSET:
print("value nicht übergeben")
if name is not _UNSET and value is not _UNSET:
print(f"{name}={value!r}")
update(name="key", value=None) # value=None ist explizit
update(name="key")key=None
value nicht übergebenPraktische Hinweise
objectist die Wurzel — jede Klasse erbt von ihr.- Nicht hashable mit Custom
__eq__: Wer__eq__definiert, muss auch__hash__(oder explizit aufNone) setzen. - Sentinel-Pattern:
object()für eindeutige Marker, die kein User-Wert je gleichen kann. __slots__einsparen:object-Instanzen haben kein__dict__— sind sehr schlank.- Verwandte Konzepte:
type,isinstance(x, object)(immer True),__bases__,__mro__.