[Python-checkins] CVS: python/nondist/peps pep-0252.txt,1.1,1.2

Guido van Rossum gvanrossum@users.sourceforge.net
Thu, 19 Apr 2001 21:02:00 -0700


Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv17416

Modified Files:
	pep-0252.txt 
Log Message:
Some more writing, specifying the core elements of the class-based
introspection API.  I'll add attribute descriptors tomorrow.


Index: pep-0252.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0252.txt,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -r1.1 -r1.2
*** pep-0252.txt	2001/04/19 21:27:25	1.1
--- pep-0252.txt	2001/04/20 04:01:57	1.2
***************
*** 2,6 ****
  Title: Making Types Look More Like Classes
  Version: $Revision$
! Author: guido@python.org (Jeremy Hylton)
  Status: Draft
  Type: Standards Track
--- 2,6 ----
  Title: Making Types Look More Like Classes
  Version: $Revision$
! Author: guido@python.org (Guido van Rossum)
  Status: Draft
  Type: Standards Track
***************
*** 48,62 ****
      of all attributes supported by a specific object, but in practice
      two conventions have appeared that together work for almost all
!     objects.
  
!     The first API is used primarily for class instances; it is also
!     used by Digital Creations's ExtensionClasses.  It assumes that all
!     data attributes of an object x are stored in the dictionary
!     x.__dict__, and that all methods and class variables can be found
!     by inspection of x's class, written as x.__class__.  Classes have
!     a __dict__ attribute, which yields a dictionary containing methods
!     and class variables defined by the class itself, and a __bases__
!     attribute, which is a tuple of base classes that must be inspected
!     recursively.  Some assumption here are:
  
      - attributes defined in the instance dict override attributes
--- 48,64 ----
      of all attributes supported by a specific object, but in practice
      two conventions have appeared that together work for almost all
!     objects.  I'll call them the class-based introspection API and the
!     type-based introspection API; class API and type API for short.
  
!     The class-based introspection API is used primarily for class
!     instances; it is also used by Digital Creations's
!     ExtensionClasses.  It assumes that all data attributes of an
!     object x are stored in the dictionary x.__dict__, and that all
!     methods and class variables can be found by inspection of x's
!     class, written as x.__class__.  Classes have a __dict__ attribute,
!     which yields a dictionary containing methods and class variables
!     defined by the class itself, and a __bases__ attribute, which is a
!     tuple of base classes that must be inspected recursively.  Some
!     assumption here are:
  
      - attributes defined in the instance dict override attributes
***************
*** 72,77 ****
      left-to-right, depth-first rule for attribute search.)
  
!     The second introspection API is supported in one form or another
!     by most built-in objects.  It uses two special attributes,
      __members__ and __methods__.  The __members__ attribute, if
      present, is a list of method names supported by the object.  The
--- 74,79 ----
      left-to-right, depth-first rule for attribute search.)
  
!     The type-based introspection API is supported in one form or
!     another by most built-in objects.  It uses two special attributes,
      __members__ and __methods__.  The __members__ attribute, if
      present, is a list of method names supported by the object.  The
***************
*** 79,86 ****
      names supported by the object.
  
!     This API is sometimes combined by a __dict__ that works the same
!     was as for instances (e.g., for function objects in Python 2.1,
!     f.__dict__ contains f's dynamic attributes, while f.__members__
!     lists the names of f's statically defined attributes).
  
      Some caution must be exercised: some objects don't list theire
--- 81,89 ----
      names supported by the object.
  
!     The type API is sometimes combined by a __dict__ that works the
!     same was as for instances (e.g., for function objects in Python
!     2.1, f.__dict__ contains f's dynamic attributes, while
!     f.__members__ lists the names of f's statically defined
!     attributes).
  
      Some caution must be exercised: some objects don't list theire
***************
*** 91,96 ****
      or not.
  
!     This second introspection API has never been carefully specified.
!     It is part of folklore, and most 3rd party extensions support it
      because they follow examples that support it.  Also, any type that
      uses Py_FindMethod() and/or PyMember_Get() in its tp_getattr
--- 94,99 ----
      or not.
  
!     The type API has never been carefully specified.  It is part of
!     Python folklore, and most third party extensions support it
      because they follow examples that support it.  Also, any type that
      uses Py_FindMethod() and/or PyMember_Get() in its tp_getattr
***************
*** 98,118 ****
      attribute names __methods__ and __members__, respectively.
  
!     Digital Creations's ExtensionClasses ignore the second
!     introspection API, and instead emulate the class instance
!     introspection API, which is more powerful.  In this PEP, I propose
!     to phase out the second API in favor of supporting the class
!     instance introspection API for all types.
! 
!     One argument in favor of the class instance introspection API is
!     that it doesn't require you to create an instance in order to find
!     out which attributes a type supports; this in turn is useful for
!     documentation processors.  For example, the socket module exports
!     the SocketType object, but this currently doesn't tell us what
!     methods are defined on socket objects.
  
- Specification
- 
-     XXX
- 
  Discussion
  
--- 101,253 ----
      attribute names __methods__ and __members__, respectively.
  
!     Digital Creations's ExtensionClasses ignore the type API, and
!     instead emulate the class API, which is more powerful.  In this
!     PEP, I propose to phase out the type API in favor of supporting
!     the class API for all types.
! 
!     One argument in favor of the class API is that it doesn't require
!     you to create an instance in order to find out which attributes a
!     type supports; this in turn is useful for documentation
!     processors.  For example, the socket module exports the SocketType
!     object, but this currently doesn't tell us what methods are
!     defined on socket objects.  Using the class API, SocketType shows
!     us exactly what the methods for socket objects are, and we can
!     even extract their docstrings, without creating a socket.  (Since
!     this is a C extension module, the source-scanning approach to
!     docstring extraction isn't feasible in this case.)
! 
! Specification of the class-based introspection API
! 
!     Objects may have two kinds of attributes: static and dynamic.  The
!     names and sometimes other properties of static attributes are
!     knowable by inspection of the object's type or class, which is
!     accessible through obj.__class__ or type(obj).  (I'm using type
!     and class interchangeably, because that's the goal of the
!     exercise.)
! 
!     (XXX static and dynamic are lousy names, because the "static"
!     attributes may actually behave quite dynamically.)
! 
!     The names and values of dynamic properties are typically stored in
!     a dictionary, and this dictionary is typically accessible as
!     obj.__dict__.  The rest of this specification is more concerned
!     with discovering the names and properties of static attributes
!     than with dynamic attributes.
! 
!     Examples of dynamic attributes are instance variables of class
!     instances, module attributes, etc.  Examples of static attributes
!     are the methods of built-in objects like lists and dictionaries,
!     and the attributes of frame and code objects (c.co_code,
!     c.co_filename, etc.).  When an object with dynamic attributes
!     exposes these through its __dict__ attribute, __dict__ is a static
!     attribute.
! 
!     In the discussion below, I distinguish two kinds of objects:
!     regular objects (e.g. lists, ints, functions) and meta-objects.
!     Meta-objects are types and classes.  Meta-objects are also regular
!     objects, but we're mostly interested in them because they are
!     referenced by the __class__ attribute of regular objects (or by
!     the __bases__ attribute of meta-objects).
! 
!     The class introspection API consists of the following elements:
! 
!     - the __class__ and __dict__ attributes on regular objects;
! 
!     - the __bases__ and __dict__ attributes on meta-objects;
! 
!     - precedence rules;
! 
!     - attribute descriptors.
! 
!     1. The __dict__ attribute on regular objects
! 
!        A regular object may have a __dict__ attribute.  If it does,
!        this should be a mapping (not necessarily a dictionary)
!        supporting at least __getitem__, keys(), and has_item().  This
!        gives the dynamic attributes of the object.  The keys in the
!        mapping give attribute names, and the corresponding values give
!        their values.
! 
!        Typically, the value of an attribute with a given name is the
!        same object as the value corresponding to that name as a key in
!        the __dict__.  In othe words, obj.__dict__['spam'] is obj.spam.
!        (But see the precedence rules below; a static attribute with
!        the same name *may* override the dictionary item.)
! 
!     2. The __class__ attribute on regular objects
! 
!        A regular object may have a __class__ attributes.  If it does,
!        this references a meta-object.  A meta-object can define static
!        attributes for the regular object whose __class__ it is.
! 
!     3. The __dict__ attribute on meta-objects
! 
!        A meta-object may have a __dict__ attribute, of the same form
!        as the __dict__ attribute for regular objects (mapping, etc).
!        If it does, the keys of the meta-object's __dict__ are names of
!        static attributes for the corresponding regular object.  The
!        values are attribute descriptors; we'll explain these later.
!        (An unbound method is a special case of an attribute
!        descriptor.)
! 
!        Becase a meta-object is also a regular object, the items in a
!        meta-object's __dict__ correspond to attributes of the
!        meta-object; however, some transformation may be applied, and
!        bases (see below) may define additional dynamic attributes.  In
!        other words, mobj.spam is not always mobj.__dict__['spam'].
!        (This rule contains a loophole because for classes, if
!        C.__dict__['spam'] is a function, C.spam is an unbound method
!        object.)
! 
!     4. The __bases__ attribute on meta-objects
! 
!        A meta-object may have a __bases__ attribute.  If it does, this
!        should be a sequence (not necessarily a tuple) of other
!        meta-objects, the bases.  An absent __bases__ is equivalent to
!        an empty sequece of bases.  There must never be a cycle in the
!        relationship between meta objects defined by __bases__
!        attributes; in other words, the __bases__ attributes define an
!        inheritance tree, where the root of the tree is the __class__
!        attribute of a regular object, and the leaves of the trees are
!        meta-objects without bases.  The __dict__ attributes of the
!        meta-objects in the inheritance tree supply attribute
!        descriptors for the regular object whose __class__ is at the
!        top of the inheritance tree.
! 
!     5. Precedence rules
! 
!        When two meta-objects in the inheritance tree both define an
!        attribute descriptor with the same name, the left-to-right
!        depth-first rule applies.  (XXX define rigorously.)
! 
!        When a dynamic attribute (one defined in a regular object's
!        __dict__) has the same name as a static attribute (one defined
!        by a meta-object in the inheritance tree rooted at the regular
!        object's __class__), the dynamic attribute *usually* wins, but
!        for some attributes the meta-object may specify that the static
!        attribute overrides the dynamic attribute.
! 
!        (We can't have a simples rule like "static overrides dynamic"
!        or "dynamic overrides static", because some static attributes
!        indeed override dynamic attributes, e.g. a key '__class__' in
!        an instance's __dict__ is ignored in favor of the statically
!        defined __class__ pointer, but on the other hand most keys in
!        inst.__dict__ override attributes defined in inst.__class__.
!        The mechanism whereby a meta-object can specify that a
!        particular attribute has precedence is not yet specified.)
! 
!     6. Attribute descriptors
! 
!        XXX
! 
!     The introspection API is a read-only API.  We don't define the
!     effect of assignment to any of the special attributes (__dict__,
!     __class__ and __bases__), nor the effect of assignment to the
!     items of a __dict__.  Generally, such assignments should be
!     considered off-limits.  An extension of this PEP may define some
!     semantics for some such assignments.  (Especially because
!     currently instances support assignment to __class__ and __dict__,
!     and classes support assignment to __bases__ and __dict__.)
  
  Discussion
  
***************
*** 142,145 ****
--- 277,284 ----
  
      XXX
+ 
+ Copyright
+ 
+     This document has been placed in the public domain.