Python Assignment– 10

Advanced Features

Basic Questions

  1. Print the results of ‘type()’, ‘id()’, and ‘dir()’ for an integer ‘n = 42’ and a string ‘s = “py”‘; also check ‘isinstance(n, int)’ and ‘isinstance(s, str)’.
  2. Define a simple class ‘User’ with attributes; create an object and use ‘getattr(obj, “name”, None)’, ‘setattr(obj, “age”, 21)’, ‘hasattr(obj, “age”)’, and ‘delattr(obj, “age”)’, printing outcomes.
  3. Demonstrate dynamic lookup: read an attribute name into ‘attr’, set it on an object with ‘setattr’, then access it with ‘getattr’ and print the value.
  4. Annotate a function ‘add(a: int, b: int) -> int’ and print ‘add.annotations’; call ‘add’ and print the result.
  5. Create a variable with a type hint ‘scores: list[int] = [10, 20, 30]’ and print ‘scores’ and the ‘.annotations’ from the module globals.
  6. Use ‘from typing import Optional’ and annotate ‘def first_item(xs: list[int]) -> Optional[int]’; implement and print results for empty and non-empty lists.
  7. Import ‘gc’ and print ‘gc.isenabled()’; call ‘gc.collect()’ and print the returned count of collected objects.
  8. Create a reference cycle (e.g., two objects referencing each other), delete user references, run ‘gc.collect()’, and print the number of collected objects.
  9. Compare list vs generator memory: create ‘[i for i in range(100000)]’ and ‘(i for i in range(100000))’; print ‘type’ and the first three items from the generator using ‘next()’.
  10. Time lazy evaluation: build ‘sum(i for i in range(1_000_00))’ and ‘sum(list(range(1_000_00)))’ using ‘time.perf_counter()’; print both durations.
  11. Set up basic logging: ‘import logging’, call ‘logging.basicConfig(level=logging.INFO)’, then log ‘info’, ‘warning’, and ‘error’ messages.
  12. Log to a file: configure ‘logging.basicConfig(filename=”app.log”, level=logging.DEBUG)’ and write a few ‘debug’ lines; open the file and print its last line.
  13. Create a minimal ‘unittest’ test case class ‘TestMath’ with a test ‘test_add’ asserting ‘2 + 3 == 5’; run tests via ‘unittest.main(argv=[“”], exit=False)’ and print the result.
  14. Add another ‘unittest’ test ‘test_raises’ that asserts a ‘ValueError’ is raised by a small function using ‘with self.assertRaises(ValueError)’.
  15. Show ‘PEP 8’ naming: write a small module-level constant ‘MAX_SIZE’, a function ‘do_work’, and a class ‘JobRunner’; print their names to confirm style.
  16. Use ‘isinstance’ with tuple of types: check whether each of ‘[1, 2.0, “x”]’ is an instance of ‘(int, float)’; print booleans.
  17. Print only callable attributes of ‘str’ by filtering ‘dir(str)’ with ‘callable(getattr(str, name))’.
  18. Demonstrate safe ‘getattr’ default: call ‘getattr(obj, “missing”, “NA”)’ and print the returned default.
  19. Annotate a dictionary ‘user: dict[str, int]’; set keys and print the mapping and a short note line ‘typed dict ready’.
  20. Show logging formatting: configure a format string ‘fmt=”%(levelname)s:%(name)s:%(message)s”‘ and log one message per level; verify the printed format.

Intermediate Questions

  1. Build a tiny metaclass ‘MetaCount’ that increments a class attribute ‘created’ each time a class using it is defined; define two classes using it and print ‘ClassA.created’ and ‘ClassB.created’.
  2. Write a metaclass ‘MetaAttrs’ that injects a method ‘describe(self)’ returning sorted attribute names; create a class with it and call ‘describe()’ on an instance.
  3. Create a dynamic proxy class ‘AttrProxy’ that forwards missing attributes via ‘getattr’ to an internal object; demonstrate by wrapping a list and calling list methods through the proxy.
  4. Use ‘setattr’ to attach a function defined at runtime to a class as a method; call the attached method from an instance and print the result.
  5. Implement attribute validation using ‘hasattr’/’getattr’: write ‘set_positive(obj, name, value)’ that raises ‘ValueError’ if ‘value <= 0’ and otherwise uses ‘setattr’; test with a simple holder class.
  6. Use ‘typing.Protocol’ to define a ‘Runnable’ protocol with ‘run(self) -> str’; implement two classes that satisfy it without inheritance and write a function that accepts ‘Runnable’ and prints results.
  7. Annotate a function with ‘typing.Iterable[int]’ and ‘typing.Iterator[int]’ return type; implement both variants and print ‘.annotations’ to compare.
  8. Demonstrate ‘gc’ debugging: enable ‘gc.set_debug(gc.DEBUG_UNCOLLECTABLE)’, create an uncollectable object by defining ‘del’ in a cycle, then run ‘gc.collect()’ and print ‘gc.garbage’.
  9. Show performance difference by timing ‘sum([i for i in range(n)])’ vs ‘sum(i for i in range(n))’ for two different ‘n’ values; print a small table-like output.
  10. Configure a logger with a child logger: create ‘logging.getLogger(“app”)’ and ‘logging.getLogger(“app.db”)’, set different levels/handlers, and log from both to show hierarchy.
  11. Add a ‘StreamHandler’ with a custom ‘Formatter’ that includes ‘%(asctime)s’ and ‘%(levelname)s)’; log two lines and print that no exception occurred.
  12. Write a small library module ‘calc.py’ with ‘add’ and ‘div’ and a ‘unittest’ suite ‘test_calc.py’ that tests normal results and exception cases; execute tests programmatically and print a summary line.
  13. Use ‘unittest.subTest’ to test multiple inputs to ‘is_even(n)’; print the count of subtests run.
  14. Write a function following ‘PEP 8’ (names, spacing, docstring) and then intentionally create a non-compliant variant; print both source strings and a short note ‘pep8 vs non-pep8’.
  15. Demonstrate dynamic default values: annotate ‘def append_item(x: list[int] | None = None) -> list[int]’ and implement the safe pattern that creates a new list when ‘x is None’; print results of two calls to show independence.
  16. Build a simple ‘timed’ decorator (non-logging) that uses ‘time.perf_counter()’ and logs duration using ‘logging.getLogger(“timed”)’; apply to a function and print one timed call.
  17. Use ‘type()’ to create a class dynamically: ‘Point = type(“Point”, (), {“init”: lambda self, x, y: (setattr(self, “x”, x), setattr(self, “y”, y))})’; instantiate and print ‘x’ and ‘y’.
  18. Explore ‘sys.getrefcount’ (read-only): create an object, print its reference count before and after appending it to a list; then delete the list and print count again.
  19. Implement a small registry via metaclass: ‘class Registry(type): registry = {}; def new(m, name, bases, ns): cls = super().new(m, name, bases, ns); m.registry[name] = cls; return cls’; define two classes and print ‘Registry.registry.keys()’.
  20. Write a function ‘safe_import(name: str) -> object’ that imports a module using ‘importlib.import_module’ inside ‘try/except ImportError’; on failure return ‘None’ and log an error; test with an existing and a fake module.

Advanced Questions

  1. Build a metaclass ‘InterfaceEnforcer’ that requires any class using it to define a method ‘process(self, data)’; if missing, raise ‘TypeError’ in ‘new’; demonstrate success and failure cases.
  2. Create a descriptor-based dynamic attribute logger: a descriptor ‘LoggedAttr’ that logs gets/sets/deletes through the ‘logging’ module; attach it to a class and show operations in logs.
  3. Implement a custom context manager ‘GCDisabled’ that disables GC in ‘enter’ and restores the prior state in ‘exit’; inside the ‘with’, perform allocations and print ‘gc.isenabled()’ before/after.
  4. Write a structural type-check using ‘typing.TypedDict’ for a config mapping; validate a runtime dict against expected keys and types, raising ‘TypeError’ on mismatch; print pass/fail.
  5. Explore deep vs shallow copy with shared substructures: create a dict with two keys referencing the same inner list; make ‘copy.copy’ and ‘copy.deepcopy’ and modify one branch; print identities and contents to show aliasing.
  6. Compose a performance benchmark harness that times three implementations of summing squares: list comprehension, generator expression, and a manual loop; print a neat table with timings and select the fastest.
  7. Configure a layered logging setup: root logger at ‘WARNING’, a module logger at ‘INFO’ with a ‘StreamHandler’, and a file logger at ‘DEBUG’ with ‘FileHandler’; emit messages at all levels and verify which appear where.
  8. Build a miniature testing harness on top of ‘unittest’ that discovers tests from a ‘tests/’ folder (using ‘unittest.TestLoader().discover’), runs them, and prints failures and total run time.
  9. Implement a metaclass ‘Frozen’ that prevents adding new attributes after initialization by overriding ‘setattr’ in the created class; demonstrate that setting an unknown attribute raises ‘AttributeError’ while existing ones can change.
  10. Write a small ‘pep8_checklist’ printer that outputs a numbered list drawn from a tuple of guidelines: ‘use snake_case for functions’, ‘CapWords for classes’, ‘spaces around operators’, ‘max line length ~ 79/88’, ‘meaningful names’, ‘docstrings for public APIs’, ‘avoid bare except’, ‘prefer f-strings’; print the list with indices.