@@ -535,6 +535,63 @@ as::
535535
536536:ticket: `4753 `
537537
538+ .. _change_4710_row :
539+
540+ The "RowProxy" is no longer a "proxy", now called ``Row ``
541+ ---------------------------------------------------------
542+
543+ Since the beginning of SQLAlchemy, the Core result objects exposed to the
544+ user are the :class: `.ResultProxy ` and ``RowProxy `` objects. The name
545+ "proxy" refers to the `GOF Proxy Pattern <https://en.wikipedia.org/wiki/Proxy_pattern >`_,
546+ emphasizing that these objects are presenting a facade around the DBAPI
547+ ``cursor `` object and the tuple-like objects returned by methods such
548+ as ``cursor.fetchone() ``; as methods on the result and row proxy objects
549+ are invoked, the underlying methods or data members of the ``cursor `` and
550+ the tuple-like objects returned are invoked.
551+
552+ In particular, SQLAlchemy's row-processing functions would be invoked
553+ as a particular column in a row is accessed. By row-processing functions,
554+ we refer to functions such as that of the :class: `.Unicode ` datatype, which under
555+ Python 2 would often convert Python string objects to Python unicode
556+ objects, as well as numeric functions that produce ``Decimal `` objects,
557+ SQLite datetime functions that produce ``datetime `` objects from string
558+ representations, as well as any-number of user-defined functions which can
559+ be created using :class: `.TypeDecorator `.
560+
561+ The rationale for this pattern was performance, where the anticipated use
562+ case of fetching a row from a legacy database that contained dozens of
563+ columns would not need to run, for example, a unicode converter on every
564+ element of each row, if only a few columns in the row were being fetched.
565+ SQLAlchemy eventually gained C extensions which allowed for additional
566+ performance gains within this process.
567+
568+ As part of SQLAlchemy 1.4's goal of migrating towards SQLAlchemy 2.0's updated
569+ usage patterns, row objects will be made to behave more like tuples. To
570+ suit this, the "proxy" behavior of :class: `.Row ` has been removed and instead
571+ the row is populated with its final data values upon construction. This
572+ in particular allows an operation such as ``obj in row `` to work as that
573+ of a tuple where it tests for containment of ``obj `` in the row itself,
574+ rather than considering it to be a key in a mapping as is the case now.
575+ For the moment, ``obj in row `` still does a key lookup,
576+ that is, detects if the row has a particular column name as ``obj ``, however
577+ this behavior is deprecated and in 2.0 the :class: `.Row ` will behave fully
578+ as a tuple-like object; lookup of keys will be via the ``._mapping ``
579+ attribute.
580+
581+ The result of removing the proxy behavior from rows is that the C code has been
582+ simplified and the performance of many operations is improved both with and
583+ without the C extensions in use. Modern Python DBAPIs handle unicode
584+ conversion natively in most cases, and SQLAlchemy's unicode handlers are
585+ very fast in any case, so the expense of unicode conversion
586+ is a non-issue.
587+
588+ This change by itself has no behavioral impact on the row, but is part of
589+ a larger series of changes in :ticket: `4710 ` which unifies the Core row/result
590+ facade with that of the ORM.
591+
592+ :ticket: `4710 `
593+
594+
538595.. _change_4449 :
539596
540597Improved column labeling for simple column expressions using CAST or similar
0 commit comments