@@ -29,8 +29,8 @@ This HowTo guide has three major sections:
29
29
Primer
30
30
^^^^^^
31
31
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.
34
34
35
35
36
36
Simple example: A descriptor that returns a constant
@@ -197,7 +197,7 @@ be recorded, giving each descriptor its own *public_name* and *private_name*::
197
197
198
198
import logging
199
199
200
- logging.basicConfig(level=logging.INFO)
200
+ logging.basicConfig(level=logging.INFO, force=True )
201
201
202
202
class LoggedAccess:
203
203
@@ -258,6 +258,10 @@ Closing thoughts
258
258
A :term: `descriptor ` is what we call any object that defines :meth: `__get__ `,
259
259
:meth: `__set__ `, or :meth: `__delete__ `.
260
260
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
+
261
265
Descriptors get invoked by the dot operator during attribute lookup. If a
262
266
descriptor is accessed indirectly with ``vars(some_class)[descriptor_name] ``,
263
267
the descriptor instance is returned without invoking it.
@@ -291,7 +295,7 @@ Validator class
291
295
A validator is a descriptor for managed attribute access. Prior to storing
292
296
any data, it verifies that the new value meets various type and range
293
297
restrictions. 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.
295
299
296
300
This :class: `Validator ` class is both an :term: `abstract base class ` and a
297
301
managed attribute descriptor::
@@ -438,12 +442,12 @@ In general, a descriptor is an object attribute with "binding behavior", one
438
442
whose attribute access has been overridden by methods in the descriptor
439
443
protocol. Those methods are :meth: `__get__ `, :meth: `__set__ `, and
440
444
: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 ` .
442
446
443
447
The default behavior for attribute access is to get, set, or delete the
444
448
attribute from an object's dictionary. For instance, ``a.x `` has a lookup chain
445
449
starting 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
447
451
looked-up value is an object defining one of the descriptor methods, then Python
448
452
may override the default behavior and invoke the descriptor method instead.
449
453
Where this occurs in the precedence chain depends on which descriptor methods
@@ -492,60 +496,76 @@ Invoking Descriptors
492
496
A descriptor can be called directly by its method name. For example,
493
497
``d.__get__(obj) ``.
494
498
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) ``
498
502
is invoked according to the precedence rules listed below.
499
503
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)) ``.
501
510
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
505
512
priority over instance variables, instance variables priority over non-data
506
513
descriptors, and assigns lowest priority to :meth: `__getattr__ ` if provided.
514
+
507
515
The full C implementation can be found in :c:func: `PyObject_GenericGetAttr() ` in
508
516
:source: `Objects/object.c `.
509
517
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::
513
523
514
- def __getattribute__(self , key):
524
+ def __getattribute__(cls , key):
515
525
"Emulate type_getattro() in Objects/typeobject.c"
516
- v = object.__getattribute__(self , key)
526
+ v = object.__getattribute__(cls , key)
517
527
if hasattr(v, '__get__'):
518
- return v.__get__(None, self )
528
+ return v.__get__(None, cls )
519
529
return v
520
530
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() `.
522
533
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) ``.
529
537
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__ `.
536
540
537
541
The 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
539
543
`Guido's Tutorial `_.
540
544
541
545
.. _`Guido's Tutorial` : https://www.python.org/download/releases/2.2.3/descrintro/#cooperation
542
546
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.
549
569
550
570
551
571
Automatic Name Notification
@@ -569,47 +589,70 @@ afterwards, :meth:`__set_name__` will need to be called manually.
569
589
Descriptor Example
570
590
------------------
571
591
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> `_.
576
595
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::
581
598
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}=?;'
585
604
586
605
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]
589
607
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()
593
611
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::
597
614
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()
609
620
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
613
656
based on the descriptor protocol.
614
657
615
658
@@ -619,7 +662,7 @@ Properties
619
662
Calling :func: `property ` is a succinct way of building a data descriptor that
620
663
triggers function calls upon access to an attribute. Its signature is::
621
664
622
- property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
665
+ property(fget=None, fset=None, fdel=None, doc=None) -> property
623
666
624
667
The documentation shows a typical use to define a managed attribute ``x ``::
625
668
@@ -695,17 +738,30 @@ Functions and Methods
695
738
Python's object oriented features are built upon a function based environment.
696
739
Using non-data descriptors, the two are merged seamlessly.
697
740
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)
704
760
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 ::
709
765
710
766
class Function:
711
767
...
@@ -716,15 +772,20 @@ object. In pure Python, it works like this::
716
772
return self
717
773
return types.MethodType(self, obj)
718
774
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
720
776
descriptor works in practice::
721
777
722
778
class D:
723
779
def f(self, x):
724
780
return x
725
781
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::
728
789
729
790
>>> D.__dict__['f']
730
791
<function D.f at 0x00C45070>
@@ -735,13 +796,8 @@ underlying function unchanged::
735
796
>>> D.f
736
797
<function D.f at 0x00C45070>
737
798
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::
745
801
746
802
>>> d = D()
747
803
>>> d.f
@@ -752,9 +808,13 @@ instance::
752
808
753
809
>>> d.f.__func__
754
810
<function D.f at 0x1012e5ae8>
811
+
755
812
>>> d.f.__self__
756
813
<__main__.D object at 0x1012e1f98>
757
814
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
+
758
818
759
819
Static Methods and Class Methods
760
820
--------------------------------
@@ -798,8 +858,8 @@ in statistical work but does not directly depend on a particular dataset.
798
858
It can be called either from an object or the class: ``s.erf(1.5) --> .9332 `` or
799
859
``Sample.erf(1.5) --> .9332 ``.
800
860
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::
803
863
804
864
class E:
805
865
@staticmethod
@@ -840,7 +900,7 @@ for whether the caller is an object or a class::
840
900
841
901
This behavior is useful whenever the function only needs to have a class
842
902
reference 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
844
904
:func: `dict.fromkeys ` creates a new dictionary from a list of keys. The pure
845
905
Python equivalent is::
846
906
0 commit comments