@@ -29,8 +29,8 @@ This HowTo guide has three major sections:
2929Primer
3030^^^^^^
3131
32- In this primer, we start with most basic possible example and then we'll add
33- new capabilities one by one.
32+ In this primer, we start with the most basic possible example and then we'll
33+ add new capabilities one by one.
3434
3535
3636Simple example: A descriptor that returns a constant
@@ -197,7 +197,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*::
197197
198198 import logging
199199
200- logging.basicConfig(level=logging.INFO)
200+ logging.basicConfig(level=logging.INFO, force=True )
201201
202202 class LoggedAccess:
203203
@@ -258,6 +258,10 @@ Closing thoughts
258258A :term: `descriptor ` is what we call any object that defines :meth: `__get__ `,
259259:meth: `__set__ `, or :meth: `__delete__ `.
260260
261+ Optionally, descriptors can have a :meth: `__set_name__ ` method. This is only
262+ used in cases where a descriptor needs to know either the class where it is
263+ created or the name of class variable it was assigned to.
264+
261265Descriptors get invoked by the dot operator during attribute lookup. If a
262266descriptor is accessed indirectly with ``vars(some_class)[descriptor_name] ``,
263267the descriptor instance is returned without invoking it.
@@ -291,7 +295,7 @@ Validator class
291295A validator is a descriptor for managed attribute access. Prior to storing
292296any data, it verifies that the new value meets various type and range
293297restrictions. If those restrictions aren't met, it raises an exception to
294- prevents data corruption at its source.
298+ prevent data corruption at its source.
295299
296300This :class: `Validator ` class is both an :term: `abstract base class ` and a
297301managed attribute descriptor::
@@ -438,12 +442,12 @@ In general, a descriptor is an object attribute with "binding behavior", one
438442whose attribute access has been overridden by methods in the descriptor
439443protocol. Those methods are :meth: `__get__ `, :meth: `__set__ `, and
440444:meth: `__delete__ `. If any of those methods are defined for an object, it is
441- said to be a descriptor.
445+ said to be a :term: ` descriptor ` .
442446
443447The default behavior for attribute access is to get, set, or delete the
444448attribute from an object's dictionary. For instance, ``a.x `` has a lookup chain
445449starting with ``a.__dict__['x'] ``, then ``type(a).__dict__['x'] ``, and
446- continuing through the base classes of ``type(a) `` excluding metaclasses . If the
450+ continuing through the base classes of ``type(a) ``. If the
447451looked-up value is an object defining one of the descriptor methods, then Python
448452may override the default behavior and invoke the descriptor method instead.
449453Where this occurs in the precedence chain depends on which descriptor methods
@@ -492,60 +496,76 @@ Invoking Descriptors
492496A descriptor can be called directly by its method name. For example,
493497``d.__get__(obj) ``.
494498
495- Alternatively, it is more common for a descriptor to be invoked automatically
496- upon attribute access. For example, ``obj.d `` looks up ``d `` in the dictionary
497- of ``obj ``. If ``d `` defines the method :meth: `__get__ `, then ``d.__get__(obj) ``
499+ But it is more common for a descriptor to be invoked automatically from
500+ attribute access. The expression ``obj.d `` looks up ``d `` in the dictionary of
501+ ``obj ``. If ``d `` defines the method :meth: `__get__ `, then ``d.__get__(obj) ``
498502is invoked according to the precedence rules listed below.
499503
500- The details of invocation depend on whether ``obj `` is an object or a class.
504+ The details of invocation depend on whether ``obj `` is an object, class, or
505+ instance of super.
506+
507+ **Objects **: The machinery is in :meth: `object.__getattribute__ `.
508+
509+ It transforms ``b.x `` into ``type(b).__dict__['x'].__get__(b, type(b)) ``.
501510
502- For objects, the machinery is in :meth: `object.__getattribute__ ` which
503- transforms ``b.x `` into ``type(b).__dict__['x'].__get__(b, type(b)) ``. The
504- implementation works through a precedence chain that gives data descriptors
511+ The implementation works through a precedence chain that gives data descriptors
505512priority over instance variables, instance variables priority over non-data
506513descriptors, and assigns lowest priority to :meth: `__getattr__ ` if provided.
514+
507515The full C implementation can be found in :c:func: `PyObject_GenericGetAttr() ` in
508516:source: `Objects/object.c `.
509517
510- For classes, the machinery is in :meth: `type.__getattribute__ ` which transforms
511- ``B.x `` into ``B.__dict__['x'].__get__(None, B) ``. In pure Python, it looks
512- like::
518+ **Classes **: The machinery is in :meth: `type.__getattribute__ `.
519+
520+ It transforms ``A.x `` into ``A.__dict__['x'].__get__(None, A) ``.
521+
522+ In pure Python, it looks like this::
513523
514- def __getattribute__(self , key):
524+ def __getattribute__(cls , key):
515525 "Emulate type_getattro() in Objects/typeobject.c"
516- v = object.__getattribute__(self , key)
526+ v = object.__getattribute__(cls , key)
517527 if hasattr(v, '__get__'):
518- return v.__get__(None, self )
528+ return v.__get__(None, cls )
519529 return v
520530
521- The important points to remember are:
531+ **Super **: The machinery is in the custom :meth: `__getattribute__ ` method for
532+ object returned by :class: `super() `.
522533
523- * descriptors are invoked by the :meth: `__getattribute__ ` method
524- * overriding :meth: `__getattribute__ ` prevents automatic descriptor calls
525- * :meth: `object.__getattribute__ ` and :meth: `type.__getattribute__ ` make
526- different calls to :meth: `__get__ `.
527- * data descriptors always override instance dictionaries.
528- * non-data descriptors may be overridden by instance dictionaries.
534+ The attribute lookup ``super(A, obj).m `` searches ``obj.__class__.__mro__ `` for
535+ the base class ``B `` immediately following ``A `` and then returns
536+ ``B.__dict__['m'].__get__(obj, A) ``.
529537
530- The object returned by ``super() `` also has a custom :meth: `__getattribute__ `
531- method for invoking descriptors. The attribute lookup ``super(B, obj).m `` searches
532- ``obj.__class__.__mro__ `` for the base class ``A `` immediately following ``B ``
533- and then returns ``A.__dict__['m'].__get__(obj, B) ``. If not a descriptor,
534- ``m `` is returned unchanged. If not in the dictionary, ``m `` reverts to a
535- search using :meth: `object.__getattribute__ `.
538+ If not a descriptor, ``m `` is returned unchanged. If not in the dictionary,
539+ ``m `` reverts to a search using :meth: `object.__getattribute__ `.
536540
537541The implementation details are in :c:func: `super_getattro() ` in
538- :source: `Objects/typeobject.c `. and a pure Python equivalent can be found in
542+ :source: `Objects/typeobject.c `. A pure Python equivalent can be found in
539543`Guido's Tutorial `_.
540544
541545.. _`Guido's Tutorial` : https://www.python.org/download/releases/2.2.3/descrintro/#cooperation
542546
543- The details above show that the mechanism for descriptors is embedded in the
544- :meth: `__getattribute__() ` methods for :class: `object `, :class: `type `, and
545- :func: `super `. Classes inherit this machinery when they derive from
546- :class: `object ` or if they have a metaclass providing similar functionality.
547- Likewise, classes can turn-off descriptor invocation by overriding
548- :meth: `__getattribute__() `.
547+ **Summary **: The details listed above show that the mechanism for descriptors is
548+ embedded in the :meth: `__getattribute__() ` methods for :class: `object `,
549+ :class: `type `, and :func: `super `.
550+
551+ The important points to remember are:
552+
553+ * Descriptors are invoked by the :meth: `__getattribute__ ` method.
554+
555+ * Classes inherit this machinery from :class: `object `, :class: `type `, or
556+ :func: `super `.
557+
558+ * Overriding :meth: `__getattribute__ ` prevents automatic descriptor calls
559+ because all the descriptor logic is in that method.
560+
561+ * :meth: `object.__getattribute__ ` and :meth: `type.__getattribute__ ` make
562+ different calls to :meth: `__get__ `. The first includes the instance and may
563+ include the class. The second puts in ``None `` for the instance and always
564+ includes the class.
565+
566+ * Data descriptors always override instance dictionaries.
567+
568+ * Non-data descriptors may be overridden by instance dictionaries.
549569
550570
551571Automatic Name Notification
@@ -569,47 +589,70 @@ afterwards, :meth:`__set_name__` will need to be called manually.
569589Descriptor Example
570590------------------
571591
572- The following code creates a class whose objects are data descriptors which
573- print a message for each get or set. Overriding :meth: `__getattribute__ ` is
574- alternate approach that could do this for every attribute. However, this
575- descriptor is useful for monitoring just a few chosen attributes::
592+ The following code is simplified skeleton showing how data descriptors could
593+ be used to implement an `object relational mapping
594+ <https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping> `_.
576595
577- class RevealAccess:
578- """A data descriptor that sets and returns values
579- normally and prints a message logging their access.
580- """
596+ The essential idea is that instances only hold keys to a database table. The
597+ actual data is stored in an external table that is being dynamically updated::
581598
582- def __init__(self, initval=None, name='var'):
583- self.val = initval
584- self.name = name
599+ class Field:
600+
601+ def __set_name__(self, owner, name):
602+ self.fetch = f'SELECT {name} FROM {owner.table} WHERE {owner.key}=?;'
603+ self.store = f'UPDATE {owner.table} SET {name}=? WHERE {owner.key}=?;'
585604
586605 def __get__(self, obj, objtype=None):
587- print('Retrieving', self.name)
588- return self.val
606+ return conn.execute(self.fetch, [obj.key]).fetchone()[0]
589607
590- def __set__(self, obj, val ):
591- print('Updating', self.name )
592- self.val = val
608+ def __set__(self, obj, value ):
609+ conn.execute(self.store, [value, obj.key] )
610+ conn.commit()
593611
594- class B:
595- x = RevealAccess(10, 'var "x"')
596- y = 5
612+ We can use the :class: `Field ` to define "models" that describe the schema for
613+ each table in a database::
597614
598- >>> m = B()
599- >>> m.x
600- Retrieving var "x"
601- 10
602- >>> m.x = 20
603- Updating var "x"
604- >>> m.x
605- Retrieving var "x"
606- 20
607- >>> m.y
608- 5
615+ class Movie:
616+ table = 'Movies' # Table name
617+ key = 'title' # Primary key
618+ director = Field()
619+ year = Field()
609620
610- The protocol is simple and offers exciting possibilities. Several use cases are
611- so common that they have been packaged into individual function calls.
612- Properties, bound methods, static methods, and class methods are all
621+ def __init__(self, key):
622+ self.key = key
623+
624+ class Song:
625+ table = 'Music'
626+ key = 'title'
627+ artist = Field()
628+ year = Field()
629+ genre = Field()
630+
631+ def __init__(self, key):
632+ self.key = key
633+
634+ An interactive session shows how data is retrieved from the database and how
635+ it can be updated::
636+
637+ >>> import sqlite3
638+ >>> conn = sqlite3.connect('entertainment.db')
639+
640+ >>> Movie('Star Wars').director
641+ 'George Lucas'
642+ >>> jaws = Movie('Jaws')
643+ >>> f'Released in {jaws.year} by {jaws.director}'
644+ 'Released in 1975 by Steven Spielberg'
645+
646+ >>> Song('Country Roads').artist
647+ 'John Denver'
648+
649+ >>> Movie('Star Wars').director = 'J.J. Abrams'
650+ >>> Movie('Star Wars').director
651+ 'J.J. Abrams'
652+
653+ The descriptor protocol is simple and offers exciting possibilities. Several
654+ use cases are so common that they have been packaged into individual function
655+ calls. Properties, bound methods, static methods, and class methods are all
613656based on the descriptor protocol.
614657
615658
@@ -619,7 +662,7 @@ Properties
619662Calling :func: `property ` is a succinct way of building a data descriptor that
620663triggers function calls upon access to an attribute. Its signature is::
621664
622- property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
665+ property(fget=None, fset=None, fdel=None, doc=None) -> property
623666
624667The documentation shows a typical use to define a managed attribute ``x ``::
625668
@@ -695,17 +738,30 @@ Functions and Methods
695738Python's object oriented features are built upon a function based environment.
696739Using non-data descriptors, the two are merged seamlessly.
697740
698- Class dictionaries store methods as functions. In a class definition, methods
699- are written using :keyword: `def ` or :keyword: `lambda `, the usual tools for
700- creating functions. Methods only differ from regular functions in that the
701- first argument is reserved for the object instance. By Python convention, the
702- instance reference is called *self * but may be called *this * or any other
703- variable name.
741+ Functions stored in class dictionaries get turned into methods when invoked.
742+ Methods only differ from regular functions in that the object instance is
743+ prepended to the other arguments. By convention, the instance is called
744+ *self * but could be called *this * or any other variable name.
745+
746+ Methods can be created manually with :class: `types.MethodType ` which is
747+ roughly equivalent to::
748+
749+ class Method:
750+ "Emulate Py_MethodType in Objects/classobject.c"
751+
752+ def __init__(self, func, obj):
753+ self.__func__ = func
754+ self.__self__ = obj
755+
756+ def __call__(self, *args, **kwargs):
757+ func = self.__func__
758+ obj = self.__self__
759+ return func(obj, *args, **kwargs)
704760
705- To support method calls , functions include the :meth: ` __get__ ` method for
706- binding methods during attribute access. This means that all functions are
707- non-data descriptors which return bound methods when they are invoked from an
708- object. In pure Python, it works like this ::
761+ To support automatic creation of methods , functions include the
762+ :meth: ` __get__ ` method for binding methods during attribute access. This
763+ means that functions are non-data descriptors which return bound methods
764+ during dotted lookup from an instance. Here's how it works ::
709765
710766 class Function:
711767 ...
@@ -716,15 +772,20 @@ object. In pure Python, it works like this::
716772 return self
717773 return types.MethodType(self, obj)
718774
719- Running the following in class in the interpreter shows how the function
775+ Running the following class in the interpreter shows how the function
720776descriptor works in practice::
721777
722778 class D:
723779 def f(self, x):
724780 return x
725781
726- Access through the class dictionary does not invoke :meth: `__get__ `. Instead,
727- it just returns the underlying function object::
782+ The function has a :term: `qualified name ` attribute to support introspection::
783+
784+ >>> D.f.__qualname__
785+ 'D.f'
786+
787+ Accessing the function through the class dictionary does not invoke
788+ :meth: `__get__ `. Instead, it just returns the underlying function object::
728789
729790 >>> D.__dict__['f']
730791 <function D.f at 0x00C45070>
@@ -735,13 +796,8 @@ underlying function unchanged::
735796 >>> D.f
736797 <function D.f at 0x00C45070>
737798
738- The function has a :term: `qualified name ` attribute to support introspection::
739-
740- >>> D.f.__qualname__
741- 'D.f'
742-
743- Dotted access from an instance calls :meth: `__get__ ` which returns a bound
744- method object::
799+ The interesting behavior occurs during dotted access from an instance. The
800+ dotted lookup calls :meth: `__get__ ` which returns a bound method object::
745801
746802 >>> d = D()
747803 >>> d.f
@@ -752,9 +808,13 @@ instance::
752808
753809 >>> d.f.__func__
754810 <function D.f at 0x1012e5ae8>
811+
755812 >>> d.f.__self__
756813 <__main__.D object at 0x1012e1f98>
757814
815+ If you have ever wondered where *self * comes from in regular methods or where
816+ *cls * comes from in class methods, this is it!
817+
758818
759819Static Methods and Class Methods
760820--------------------------------
@@ -798,8 +858,8 @@ in statistical work but does not directly depend on a particular dataset.
798858It can be called either from an object or the class: ``s.erf(1.5) --> .9332 `` or
799859``Sample.erf(1.5) --> .9332 ``.
800860
801- Since staticmethods return the underlying function with no changes, the example
802- calls are unexciting::
861+ Since static methods return the underlying function with no changes, the
862+ example calls are unexciting::
803863
804864 class E:
805865 @staticmethod
@@ -840,7 +900,7 @@ for whether the caller is an object or a class::
840900
841901This behavior is useful whenever the function only needs to have a class
842902reference and does not care about any underlying data. One use for
843- classmethods is to create alternate class constructors. The classmethod
903+ class methods is to create alternate class constructors. The classmethod
844904:func: `dict.fromkeys ` creates a new dictionary from a list of keys. The pure
845905Python equivalent is::
846906
0 commit comments