Student Activity

Student Activity Guide:

1) Understanding and Implementing Decorators

  • Create a simple decorator that logs function execution.

  • Implement a decorator to measure execution time of a function.

Example Code:

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Executing {func.__name__}...")
        return func(*args, **kwargs)
    return wrapper

@log_decorator
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Student Exercise: Implement a decorator that counts the number of times a function is called.

2) Understanding and Implementing Generators

  • Create a generator function to yield even numbers up to a limit.

  • Use a generator to read a large file line by line.

Example Code:

def even_numbers(limit):
    for i in range(2, limit + 1, 2):
        yield i

for num in even_numbers(10):
    print(num)

Student Exercise: Implement a Fibonacci sequence generator.

3) Understanding and Implementing Descriptors

  • Create a descriptor to validate attribute values.

  • Implement a descriptor to enforce read-only attributes.

Example Code:

class Descriptor:
    def __init__(self, name):
        self.name = name
    
    def __get__(self, instance, owner):
        return instance.__dict__.get(self.name, None)
    
    def __set__(self, instance, value):
        if isinstance(value, int) and value > 0:
            instance.__dict__[self.name] = value
        else:
            raise ValueError("Value must be a positive integer")

class Person:
    age = Descriptor("age")

p = Person()
p.age = 30
print(p.age)  # Output: 30

Student Exercise: Implement a descriptor that ensures an attribute is always a string.

4) Using @property, @staticmethod, and @classmethod

  • Demonstrate the use of @property for read-only attributes.

  • Implement @staticmethod and @classmethod to modify class behavior.

Example Code:

class Example:
    def __init__(self, value):
        self._value = value
    
    @property
    def value(self):
        return self._value
    
    @staticmethod
    def static_method():
        print("Static method called")
    
    @classmethod
    def class_method(cls):
        print("Class method called")

ex = Example(10)
print(ex.value)  # Output: 10
Example.static_method()
Example.class_method()

Student Exercise: Implement a class with @property for read-only attributes and @classmethod to modify class-level attributes.

5) Performance Benefits of Generators

  • Compare memory usage of lists and generators.

  • Implement a generator that filters large dataset values efficiently.

Example Code:

import sys

list_comp = [i for i in range(1000000)]
gen_exp = (i for i in range(1000000))

print(sys.getsizeof(list_comp))  # High memory usage
print(sys.getsizeof(gen_exp))  # Low memory usage

Student Exercise: Compare execution time of list comprehensions vs generators for large datasets.

Last updated