>Python: Advanced 2

Contents

Introspection & Reflection: inspect module

Explore Python's ability to examine objects, functions, and classes at runtime using the inspect module and built-in functions.

import inspect

def foo(x, y=10):
    '''Adds two numbers.'''
    return x + y

# Get function signature
sig = inspect.signature(foo)
print(sig)  # (x, y=10)

# Get docstring
print(inspect.getdoc(foo))

# List all members of a module
print(inspect.getmembers(foo))

# Check if an object is a function
print(inspect.isfunction(foo))

# Reflection: getattr, hasattr, setattr
class Bar:
    def __init__(self):
        self.value = 42

b = Bar()
print(hasattr(b, 'value'))
setattr(b, 'value', 100)
print(getattr(b, 'value'))

Memory Management & Garbage Collection

Understand how Python manages memory, reference counting, and garbage collection.

import sys
import gc

# Reference counting
a = []
b = a
print(sys.getrefcount(a))  # At least 2

# Garbage collection
class Node:
    def __init__(self):
        self.ref = None

n1 = Node()
n2 = Node()
n1.ref = n2
n2.ref = n1  # Circular reference

del n1
del n2
gc.collect()  # Force garbage collection

# Disable/enable GC
gc.disable()
gc.enable()

__slots__ & Memory Optimizations

Use __slots__ to reduce memory usage in classes. See the full playlist for more details!

# Without __slots__
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2)
print(p.__dict__)

# With __slots__
class PointSlots:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y

ps = PointSlots(3, 4)
# print(ps.__dict__)  # AttributeError
print(ps.x, ps.y)

# Memory comparison
import sys
print(sys.getsizeof(p))
print(sys.getsizeof(ps))

Concurrency: Threading, Multiprocessing, Asyncio

Learn about Python's concurrency models: threads, processes, and async coroutines.

import threading
import multiprocessing
import asyncio
import time

# Threading example
def thread_func():
    print("Thread running")
    time.sleep(1)
    print("Thread done")

t = threading.Thread(target=thread_func)
t.start()
t.join()

# Multiprocessing example
def proc_func():
    print("Process running")
    time.sleep(1)
    print("Process done")

if __name__ == "__main__":
    p = multiprocessing.Process(target=proc_func)
    p.start()
    p.join()

# Asyncio example
async def async_func():
    print("Async start")
    await asyncio.sleep(1)
    print("Async end")

asyncio.run(async_func())