Modifying Python Objects within the SQLAlchemy Framework

Samie Azad
3 min readMay 10, 2019

--

In Python, an Object-Oriented Programming (OOP) language, everything is an object. Objects have attributes, either fields or methods, which can either hold information about the object or define an action the object may perform. Modification, or retrieval which is outside of the scope of this article, of these attributes can be achieved through a few different routes. Every object has a __dict__ attribute which is a dictionary of the names of its attributes and their values. The __dict__ attribute is accessible for class keywords as well, where you will see class attributes and methods defined. Python also allows for dot notation such as:

[object].[attribute] = [value] 

to modify the attributes of an object. This syntax is intuitive and readable so it is used most often. Python also has built-in [action]attr methods, which can perform dot notation tasks when the literal interpretation of dot-notation makes its use impractical. Dot notation requires the name of the attribute after the dot, therefore variables cannot be used in place of the attribute name. The implication of this limitation is that dot notation cannot be used in cases where the attribute name must be accessed through a variable, such as within loops or storing user input in a variable. The object-modification method we will witness in this article is:

setattr([object], [key], [value])

Setattr() is essentially synonymous to dot notation, but we will see its contrast with __dict__ in the context of SQLAlchemy. SQLAlchemy can “see” the changes made when using setattr(), while it can not “see” changes made when using __dict__.

When using __dict__ and setattr() in the context of Python, the results are the same because we are essentially editing each object’s attribute dictionary which is represented by __dict__. In the context of SQLAlchemy we see a difference due to the way SQLAlchemy “sees” the changes. SQLAlchemy overrides the __setattr__ method, the method called when using dot notation, in a few of its classes. __setattr__ is a method of the generic object class in Python. The object class allows for the use of descriptors, necessary object attributes, etc. __setattr__ is an instance attribute magic method equivalent to the setattr() method. SQLAlchemy defines its own class, “DeclarativeMeta” which redefines __setattr__ to use its own set_attribute method. This method essentially allows the SQLAlchemy state manager to handle the background process of updating the _sa_instance_attribute of a database object in order to keep track of any changes before they are committed to the database. By wrapping the set_attribute method inside of a redefined __setattr__ method, SQLAlchemy hijacks the behavior of __setattr__ through its own descriptor defined in the Column class, a sub-class of the DeclarativeMeta class. By using descriptors, SQLAlchemy can model the modification of an object as an attribute change without the limitations of dot notation and with the necessary recording of object changes for induction into the database.

[Object].[ColumnObject] = [new_value] === 
[Object].[ColumnObject].__setattr__([key], [new_value])

So, when using __dict__ the whole __setattr__ process is bypassed therefore SQLAlchemy can not “see” the changes that are made because __setattr__ is not called. There is a new instance attribute in this case which masks the original class attribute of the Column object. The masking means there will not be any recording of the changes made even if dot notation is used afterward because the attribute has completely changed. Without the object that overrides __setattr__ being set, SQLAlchemy can not commit any changes made to the object.

--

--