>>> mark =Immutable( 'Botany','Mark Watney') >>> mark.dept 'Botany' >>> mark.dept ='Space Pirate' Traceback (most recent call last): ... AttributeError: can't set attribute >>> mark.location='Mars ' Traceback (most recent call last): ... AttributeError: 'Immutable' object has no attribute 'location' from functoolsimport cached_property classCP : __slots__ =() # Eliminates the instance dict @cached_property # Requires an instance dict def pi(self): return 4*sum(( -1.0 )**n /(2.0 *n +1.0 ) for n in reversed(range(100_000 ))) >>> CP() .pi Traceback (most recent call last): ... TypeError: No '__dict__' attribute on 'CP' instance to cache 'pi' property. null=object() classMember : def __init__ (self, name, clsname, offset): 'Emulate PyMemberDef in Include/structmember.h ' (continues on next page) 18 It is not possible to create an exact drop-in pure Python version of$_{__slots__}$ because it requires direct access to C structures and control over object memory allocation. However, we can build a mostly faithful simulation where the actual C structure for slots is emulated by a private$_{_slotvalues}$ list. Reads and writes to that private structure are managed by member descriptors: 3. Saves memory. On a 64-bit Linux build, an instance with two attributes takes 48 bytes with$_{__slots__}$ and 152 bytes without. This flyweight design pattern likely only matters when a large number of instances are going to be created. 4. Blocks tools like$_{functools.cached_property()}$ which require an instance dictionary to function cor- rectly: classImmutable : __slots__ =('_dept','_name') # Replace the instance dictionary def __init__ (self, dept, name): self._dept=dept # Store to private attribute self._name=name # Store to private attribute @property # Read-only descriptor def dept(self): return self._dept @property def name(self): # Read-only descriptor return self._name