The answer, at least with ArcPy Data Access cursors, is that you cannot avoid the behavior you are seeing because of a known defect with ArcPy Data Access cursors. From BUG-000091314: When using the data access module and an update curs..:
Bug BUG-000091314
Synopsis
When using the data access module and an update cursor, row values
cannot be updated to null.
Alternate Solution
Use the old update cursor or use the Calculate Field geoprocessing tool.
This defect was logged in 2015, which means it was logged right after Pro 1.0 was released, and the defect still exists today in Pro 2.9.x, so I would not be holding your breath for a resolution any time soon.
UPDATE
Esri finally addressed this defect in Pro 3.1 through the introduction of a new explicit
parameter in the ArcPy DA InsertCursor - ArcGIS Pro | Documentation and UpdateCursor - ArcGIS Pro | Documentation.
Modifying the OP's code using the new parameter to force nullable fields to accept NULL:
with a.da.UpdateCursor(table, field_list, where_clause, explicit=True) as cursor:
for row in cursor:
for i in range(0, len(row)):
if row[i] == 0:
row[i] = None
cursor.updateRow(row)
row = [None if val==1 else val for val in row]
row = None
but as a result there are "1" in cells not "Null". It's because default value for the field =1