# 168. \_\_slots\_\_ for Memory EfficiencyPage

**Snippet 1: Basic Usage of `__slots__`**

```python
class Person:
    __slots__ = ('name', 'age')

    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 30)
print(p.name, p.age)
# p.address = "New York"  # AttributeError: 'Person' object has no attribute 'address'
```

***

**Snippet 2: Memory Comparison with and without `__slots__`**

```python
import sys

class WithoutSlots:
    def __init__(self, name, age):
        self.name = name
        self.age = age

class WithSlots:
    __slots__ = ('name', 'age')

    def __init__(self, name, age):
        self.name = name
        self.age = age

obj1 = WithoutSlots("Alice", 30)
obj2 = WithSlots("Alice", 30)

print(sys.getsizeof(obj1.__dict__))  # Memory used without __slots__
print(sys.getsizeof(obj2))          # Memory used with __slots__
```

***

**Snippet 3: Preventing Dynamic Attribute Addition**

```python
class FixedAttributes:
    __slots__ = ('a', 'b')

obj = FixedAttributes()
obj.a = 10
obj.b = 20
# obj.c = 30  # AttributeError: 'FixedAttributes' object has no attribute 'c'
```

***

**Snippet 4: Using `__slots__` in Inheritance (Single Level)**

```python
class Parent:
    __slots__ = ('x',)

class Child(Parent):
    __slots__ = ('y',)

obj = Child()
obj.x = 5
obj.y = 10
print(obj.x, obj.y)
```

***

**Snippet 5: Combining `__slots__` with Class Variables**

```python
class Config:
    __slots__ = ('host', 'port')
    version = "1.0"  # Class variable

c = Config()
c.host = "localhost"
c.port = 8080
print(Config.version, c.host, c.port)
```

***

**Snippet 6: Attempting to Use `__dict__` with `__slots__`**

```python
class Example:
    __slots__ = ('attr1', 'attr2')

obj = Example()
obj.attr1 = "Hello"
obj.attr2 = "World"
# print(obj.__dict__)  # AttributeError: 'Example' object has no attribute '__dict__'
```

***

**Snippet 7: Using `__slots__` with Properties**

```python
class Person:
    __slots__ = ('_name', '_age')

    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @property
    def age(self):
        return self._age

p = Person("Alice", 30)
print(p.name, p.age)
```

***

**Snippet 8: Multiple Inheritance and `__slots__`**

```python
class A:
    __slots__ = ('a',)

class B:
    __slots__ = ('b',)

class C(A, B):
    __slots__ = ('c',)

obj = C()
obj.a = 1
obj.b = 2
obj.c = 3
print(obj.a, obj.b, obj.c)
```

***

**Snippet 9: Performance Measurement with `__slots__`**

```python
import timeit

class WithoutSlots:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class WithSlots:
    __slots__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

def create_without_slots():
    obj = WithoutSlots(1, 2)

def create_with_slots():
    obj = WithSlots(1, 2)

print("Without __slots__:", timeit.timeit(create_without_slots, number=1000000))
print("With __slots__:", timeit.timeit(create_with_slots, number=1000000))
```

***

**Snippet 10: Extending `__slots__` Dynamically (Workaround)**

```python
class DynamicSlots:
    __slots__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

obj = DynamicSlots(1, 2)
setattr(obj, 'z', 3)  # Raises AttributeError
```

***
