6. Interview Questions- Events and Internals

Source: https://docs.sqlalchemy.org/en/20/orm/extending.html


1. What is the purpose of extending the SQLAlchemy ORM?

Answer: To customize behavior such as object instantiation, attribute access, change tracking, or mapping configuration beyond default behavior.


2. What are ORM events in SQLAlchemy?

Answer: Hooks that let you intercept and respond to changes in ORM objects or sessions—e.g., object load, insert, update, delete, etc.


3. How do you register an event for when a class is loaded from the database?

Answer:

from sqlalchemy import event

@event.listens_for(MyClass, "load")
def receive_load(instance, context):
    print(f"{instance} was loaded")

4. What does the @event.listens_for(..., 'init') decorator do?

Answer: It intercepts when a new instance of a class is created (before it's added to a session or persisted).


5. What’s the difference between load and refresh events?

Answer:

  • load: Triggered when the object is loaded from the DB the first time.

  • refresh: Triggered when an existing instance is reloaded from the DB (e.g., via refresh()).


6. How can you track changes to a particular attribute?

Answer:


7. What event is used to intercept before insert or update in ORM?

Answer:


8. Can you intercept attribute-level access (e.g., __get__, __set__) using ORM tools?

Answer: Yes, using attribute instrumentation events like "set" and "init_scalar".


9. What does the "append" event on a relationship do?

Answer: It triggers when a new item is added to a collection-based relationship.


10. How can you perform actions when an object is added to a relationship?

Answer:


11. What is the use of __init__() vs. @event.listens_for(..., 'init')?

Answer: __init__() is Python-native object creation. The init event allows SQLAlchemy to instrument or wrap creation dynamically.


12. How do you extend a mapped class with mixins in SQLAlchemy?

Answer: Define shared logic (columns, methods, relationships) in a base class without __tablename__, and inherit it in ORM classes.


13. What is the difference between a mixin and an abstract base in SQLAlchemy ORM?

Answer:

  • Mixin: Reusable logic; not mapped by itself.

  • Abstract base: May be mapped, but marked with __abstract__ = True.


14. Can attribute-level events be registered after class definition?

Answer: Yes, via the event.listen() API or using @event.listens_for() decorator.


15. How do you track when a relationship collection is cleared?

Answer:


16. How do you prevent a certain value from being assigned to a field?

Answer: Use the "set" attribute event and raise an exception based on the value.


17. What is a class manager in SQLAlchemy ORM internals?

Answer: It’s an internal object that manages instrumentation, lifecycle events, and tracking for ORM-mapped classes.


18. How does SQLAlchemy know which attributes are mapped and instrumented?

Answer: Through the class’s mapper and the instrumentation system via DeclarativeBase or registry().


19. Can you define global listeners that affect all ORM classes?

Answer: Yes, by targeting the base Mapper or InstanceEvents on all mapped classes.


20. What’s the difference between instance-level and class-level event listeners?

Answer:

  • Instance-level: React to changes on specific instances (e.g., attribute set).

  • Class-level: Affect all instances of the class during lifecycle phases like insert, load, etc.


21. How do you intercept an object being marked as deleted?

Answer:


22. What event can you use to automatically populate a timestamp on insert?

Answer:


23. How do you instrument a class without using declarative?

Answer: You can use registry().map_imperatively() and still attach class- or attribute-level listeners.


24. What’s the use of @event.listens_for(Mapper, 'after_configured')?

Answer: It lets you execute logic after all ORM mappings have been configured (e.g., apply validations or constraints globally).


25. What does the "append" event emit in terms of arguments?

Answer: It passes the target (the parent), value (the new child), and initiator (instrumentation metadata).


26. Can you listen to events on unmapped classes?

Answer: No, ORM-specific events only apply to mapped classes or instrumented attributes.


27. What’s the difference between "set" and "modified" events on an attribute?

Answer:

  • "set": Triggers when a value is assigned.

  • "modified": Triggers when a value changes meaningfully (often used for dirty tracking).


28. How do you dynamically add a listener at runtime?

Answer:


29. What is the init_scalar event used for?

Answer: It fires when a new instance is constructed and scalar attributes are initialized (typically None or default values).


30. How can you track whether a particular column was changed during a session?

Answer: Use attribute-level "set" event or use sqlalchemy.inspect(obj).attrs.column_name.history.


31. How do you mark a mixin as declarative-safe?

Answer: Use the @declarative_mixin decorator:


32. What does @declarative_mixin offer over a plain class?

Answer: It signals SQLAlchemy that the class is intended as a mixin for mapping and avoids accidental mapping of the mixin itself.


33. Can @event.listens_for be used on hybrid properties?

Answer: Yes, but it should be attached to the underlying attribute, not the property method.


34. How do you register an event on all mappers globally?

Answer:


35. What is the initiator argument in attribute events?

Answer: It carries metadata about the operation, including the key name, parent object, and whether the event is user-triggered.


36. Can listeners be removed once added?

Answer: Yes, using event.remove() with the same signature used to register.


37. What’s the purpose of dispatch on ORM classes or attributes?

Answer: It exposes the event registry for that target, allowing inspection or programmatic listener attachment.


38. How can you use ORM events to implement soft deletes?

Answer: Intercept the before_delete event, cancel the actual delete, and instead set a deleted flag:


39. How can you override attribute access behavior in an ORM-mapped class?

Answer: Use descriptors or attribute-level instrumentation with events like "set" and "get".


40. What is the role of the MapperEvents class in SQLAlchemy?

Answer: It defines the set of ORM-level event names like before_insert, after_update, before_flush, etc., for mapped classes.


41. What is the purpose of __declare_last__() in a mapped class?

Answer: It is a class method that SQLAlchemy calls after all mappings are configured. It’s often used to register class-specific events or constraints.


42. Can you override default behavior of an attribute (e.g., validation) using events?

Answer: Yes. Use the "set" event to intercept assignment and apply validation logic.


43. What’s the role of MapperExtension in SQLAlchemy?

Answer: MapperExtension was a legacy system used to hook into ORM behavior. It is now replaced by the modern event system (e.g., before_insert, after_update).


44. Can @event.listens_for be applied to both attributes and relationships?

Answer: Yes. It can listen to scalar fields ("set", "modified") and collection-based relationships ("append", "remove", "bulk_replace").


45. What event should you use to modify values coming from the database during object load?

Answer: The "load" event on the mapped class:


46. How do you make a declarative mixin class that contributes indexes or constraints?

Answer: Use __table_args__ in the mixin:


47. How can you use events to inject behavior across multiple ORM classes?

Answer: Attach listeners to the base Mapper class or apply the same mixin with __declare_last__() in child classes.


48. What’s the purpose of the bulk_replace event on relationships?

Answer: It fires when a full list of items is replaced on a collection-based relationship, allowing inspection or intervention.


49. Can you attach listeners to hybrid or computed properties?

Answer: Direct event listening is not available on @hybrid_property, but you can hook into the underlying columns or override the property logic.


50. How does SQLAlchemy handle multiple mixins with overlapping attributes?

Answer: The last mixin in the MRO (method resolution order) overrides earlier ones. Conflicts should be resolved manually to avoid ambiguous behavior.


Last updated