[Python-checkins] r54382 - peps/trunk/pep-0000.txt peps/trunk/pep-3100.txt peps/trunk/pep-3115.txt

guido.van.rossum python-checkins at python.org
Wed Mar 14 18:52:23 CET 2007


Author: guido.van.rossum
Date: Wed Mar 14 18:52:19 2007
New Revision: 54382

Added:
   peps/trunk/pep-3115.txt   (contents, props changed)
Modified:
   peps/trunk/pep-0000.txt
   peps/trunk/pep-3100.txt
Log:
Add PEP 3115: Metaclasses in Py3k, by Talin.
Updated PEP 0 to list PEP 3114: next -> __next__, by Ping.


Modified: peps/trunk/pep-0000.txt
==============================================================================
--- peps/trunk/pep-0000.txt	(original)
+++ peps/trunk/pep-0000.txt	Wed Mar 14 18:52:19 2007
@@ -112,6 +112,8 @@
  S   754  IEEE 754 Floating Point Special Values       Warnes
  S  3101  Advanced String Formatting                   Talin
  S  3108  Standard Library Reorganization              Cannon
+ S  3114  Renaming iterator.next() to iterator.__next__() Yee
+ S  3115  Metaclasses in Python 3000                   Talin
 
 
  Finished PEPs (done, implemented in Subversion)
@@ -462,6 +464,8 @@
  SA 3111  Simple input built-in in Python 3000         Roberge
  SA 3112  Bytes literals in Python 3000                Orendorff
  SA 3113  Removal of Tuple Parameter Unpacking         Cannon
+ S  3114  Renaming iterator.next() to iterator.__next__() Yee
+ S  3115  Metaclasses in Python 3000                   Talin
 
 
 Key

Modified: peps/trunk/pep-3100.txt
==============================================================================
--- peps/trunk/pep-3100.txt	(original)
+++ peps/trunk/pep-3100.txt	Wed Mar 14 18:52:19 2007
@@ -65,7 +65,7 @@
 
 * True division becomes default behavior [#pep238]_ [done]
 * ``exec`` as a statement is not worth it -- make it a function [done]
-* (Maybe) add optional declarations for static typing [#pep3107]_ [10]_
+* Add optional declarations for static typing [#pep3107]_ [10]_ [done]
 * Support only new-style classes; classic classes will be gone [1]_ [done]
 * Replace ``print`` by a function [14]_  [#pep3105]_ [done]
 * The ``softspace`` attribute of files goes away. [done]

Added: peps/trunk/pep-3115.txt
==============================================================================
--- (empty file)
+++ peps/trunk/pep-3115.txt	Wed Mar 14 18:52:19 2007
@@ -0,0 +1,284 @@
+PEP: 3115
+Title: Metaclasses in Python 3000
+Version: $Revision$
+Last-Modified: $Date$
+Author: Talin <talin at acm.org>
+Status: Draft
+Type: Standards
+Content-Type: text/plain
+Created: 07-Mar-2007
+Python-Version: 3.0
+Post-History: 11-March-2007, 14-March-2007
+
+Abstract
+
+     This PEP proposes changing the syntax for declaring metaclasses,
+     and alters the semantics for how classes with metaclasses are
+     constructed.
+
+
+Rationale
+
+     There are two rationales for this PEP, both of which are somewhat
+     subtle.
+
+     The primary reason for changing the way metaclasses work, is that
+     there are a number of interesting use cases that require the
+     metaclass to get involved earlier in the class construction process
+     than is currently possible. Currently, the metaclass mechanism is
+     essentially a post-processing step. With the advent of class
+     decorators, much of these post-processing chores can be taken over
+     by the decorator mechanism.
+
+     In particular, there is an important body of use cases where it
+     would be useful to preserve the order in which a class members are
+     declared. Ordinary Python objects store their members in a
+     dictionary, in which ordering is unimportant, and members are
+     accessed strictly by name. However, Python is often used to
+     interface with external systems in which the members are organized
+     according to an implicit ordering. Examples include declaration of C
+     structs; COM objects; Automatic translation of Python classes into
+     IDL or database schemas, such as used in an ORM; and so on.
+
+     In such cases, it would be useful for a Python programmer to specify
+     such ordering directly using the declaration order of class members.
+     Currently, such orderings must be specified explicitly, using some
+     other mechanism (see the ctypes module for an example.)
+
+     Unfortunately, the current method for declaring a metaclass does
+     not allow for this, since the ordering information has already been
+     lost by the time the metaclass comes into play. By allowing the
+     metaclass to get involved in the class construction process earlier,
+     the new system allows the ordering or other early artifacts of
+     construction to be preserved and examined.
+
+     The other, weaker, rationale is purely cosmetic: The current method
+     for specifying a metaclass is by assignment to the special variable
+     __metaclass__, which is considered by some to be aesthetically less
+     than ideal. Others disagree strongly with that opinion. This PEP
+     will not address this issue, other than to note it, since aesthetic
+     debates cannot be resolved via logical proofs.
+
+
+Specification
+
+     In the new model, the syntax for specifying a metaclass is via a
+     keyword argument in the list of base classes:
+
+       class Foo(base1, base2, metaclass=mymeta):
+         ...
+
+     Additional keywords will also be allowed here, and will be passed to
+     the metaclass, as in the following example:
+
+       class Foo(base1, base2, metaclass=mymeta, private=True):
+         ...
+
+     Note that this PEP makes no attempt to define what these other
+     keywords might be - that is up to metaclass implementors to
+     determine.
+
+     More generally, the parameter list passed to a class definition will
+     now support all of the features of a function call, meaning that you
+     can now use *args and **kwargs-style arguments in the class base
+     list:
+
+        class Foo(*bases, **kwds):
+           ...
+
+Invoking the Metaclass
+
+     In the current metaclass system, the metaclass object can be any
+     callable type. This does not change, however in order to fully
+     exploit all of the new features the metaclass will need to have an
+     extra attribute which is used during class pre-construction.
+
+     This attribute is named __prepare__, which is invoked as a function
+     before the evaluation of the class body. The __prepare__ function
+     takes two positional arguments, and an arbitrary number of keyword
+     arguments. The two positional arguments are:
+
+       'name' - the name of the class being created.
+       'bases' - the list of base classes.
+
+     The interpreter always tests for the existence of __prepare__ before
+     calling it; If it is not present, then a regular dictionary is used,
+     as illustrated in the following Python snippet.
+
+     def prepare_class(name, *bases, metaclass=type, **kwargs):
+        prepare = getattr(metaclass, '__prepare__', None)
+        if prepare is not None:
+           return prepare(name, bases, **kwargs)
+        else:
+           return dict()
+
+     The example above illustrates how the arguments to 'class' are
+     interpreted. The class name is the first argument, followed by
+     an arbitrary length list of base classes. After the base classes,
+     there may be one or more keyword arguments, one of which can be
+     'metaclass'. Note that the 'metaclass' argument is not included
+     in kwargs, since it is filtered out by the normal parameter
+     assignment algorithm. (Note also that 'metaclass' is a keyword-
+     only argument as per PEP 3102 [6].)
+
+     __prepare__ returns a dictionary-like object which is used to store
+     the class member definitions during evaluation of the class body.
+     In other words, the class body is evaluated as a function block
+     (just like it is now), except that the local variables dictionary
+     is replaced by the dictionary returned from __prepare__. This
+     dictionary object can be a regular dictionary or a custom mapping
+     type. It does not need to implement the full dictionary interface;
+     only the ability to insert items and retrieve them are
+     required. (Note: double check that this is true).
+
+     Note that __prepare__ is generally a class method, not an instance
+     method because it is called before the metaclass instance (i.e. the
+     class itself) is created.
+
+     Once the class body has finished evaluating, the metaclass will be
+     called (as a callable) with the class dictionary, which is no
+     different from the current metaclass mechanism.
+
+     Typically, a metaclass will create a custom dictionary - either a
+     subclass of dict, or a wrapper around it - that will contain
+     additional properties that are set either before or during the
+     evaluation of the class body. Then in the second phase, the
+     metaclass can use these additional properties to further customize
+     the class.
+
+     An example would be a metaclass that uses information about the
+     ordering of member declarations to create a C struct. The metaclass
+     would provide a custom dictionary that simply keeps a record of the
+     order of insertions. This does not need to be a full 'ordered dict'
+     implementation, but rather just a Python list of (key,value) pairs
+     that is appended to for each insertion.
+
+     Note that in such a case, the metaclass would be required to deal
+     with the possibility of duplicate keys, but in most cases that is
+     trivial. The metaclass can use the first declaration, the last,
+     combine them in some fashion, or simply throw an exception. It's up
+     to the metaclass to decide how it wants to handle that case.
+
+Example:
+
+     Here's a simple example of a metaclass which creates a list of
+     the names of all class members, in the order that they were
+     declared:
+
+     # The metaclass
+     class OrderedClass(type):
+
+         # The custom dictionary
+         class member_table(dict):
+            def __init__(self):
+               self.member_names = []
+
+            def __setitem__(self, key, value):
+               # if the key is not already defined, add to the
+               # list of keys.
+               if key not in self:
+                  self.member_names.append(key)
+
+               # Call superclass
+               dict.setitem(self, key, value)
+
+         # The prepare function
+         @classmethod
+         def __prepare__(metacls, name, bases):  # No keywords in this case
+            return metacls.member_table()
+
+         # The metaclass invocation
+         def __init__(self, name, bases, classdict):
+            # Note that we replace the classdict with a regular
+            # dict before passing it to the superclass, so that we
+            # don't continue to record member names after the class
+            # has been created.
+            result = type(name, bases, dict(classdict))
+            result.member_names = classdict.member_names
+            return result
+
+     class MyClass(metaclass=OrderedClass):
+        # method1 goes in array element 0
+        def method1(self):
+           pass
+
+        # method2 goes in array element 1
+        def method2(self):
+           pass
+
+Alternate Proposals
+
+     Josiah Carlson proposed using the name 'type' instead of
+     'metaclass', on the theory that what is really being specified is
+     the type of the type. While this is technically correct, it is also
+     confusing from the point of view of a programmer creating a new
+     class. From the application programmer's point of view, the 'type'
+     that they are interested in is the class that they are writing; the
+     type of that type is the metaclass.
+
+     There were some objections in the discussion to the 'two-phase'
+     creation process, where the metaclass is invoked twice, once to
+     create the class dictionary and once to 'finish' the class. Some
+     people felt that these two phases should be completely separate, in
+     that there ought to be separate syntax for specifying the custom
+     dict as for specifying the metaclass. However, in most cases, the
+     two will be intimately tied together, and the metaclass will most
+     likely have an intimate knowledge of the internal details of the
+     class dict. Requiring the programmer to insure that the correct dict
+     type and the correct metaclass type are used together creates an
+     additional and unneeded burden on the programmer.
+
+     Another good suggestion was to simply use an ordered dict for all
+     classes, and skip the whole 'custom dict' mechanism. This was based
+     on the observation that most use cases for a custom dict were for
+     the purposes of preserving order information. However, this idea has
+     two drawbacks, first because it means that an ordered dict
+     implementation would have to be added to the set of built-in types
+     in Python, and second because it would impose a slight speed (and
+     complexity) penalty on all class declarations.
+
+
+Backwards Compatibility
+
+     It would be possible to leave the existing __metaclass__ syntax in
+     place. Alternatively, it would not be too difficult to modify the
+     syntax rules of the Py3K translation tool to convert from the old to
+     the new syntax.
+
+
+References
+
+     [1] [Python-3000] Metaclasses in Py3K (original proposal)
+ 
+http://mail.python.org/pipermail/python-3000/2006-December/005030.html
+
+     [2] [Python-3000] Metaclasses in Py3K (Guido's suggested syntax)
+ 
+http://mail.python.org/pipermail/python-3000/2006-December/005033.html
+
+     [3] [Python-3000] Metaclasses in Py3K (Objections to two-phase init)
+ 
+http://mail.python.org/pipermail/python-3000/2006-December/005108.html
+
+     [4] [Python-3000] Metaclasses in Py3K (Always use an ordered dict)
+ 
+http://mail.python.org/pipermail/python-3000/2006-December/005118.html
+
+     [5] PEP 359: The 'make' statement -
+         http://www.python.org/dev/peps/pep-0359/
+
+     [6] PEP 3102: Keyword-only arguments -
+         http://www.python.org/dev/peps/pep-3102/
+
+Copyright
+
+     This document has been placed in the public domain.
+
+
+Local Variables:
+mode: indented-text
+indent-tabs-mode: nil
+sentence-end-double-space: t
+fill-column: 70
+coding: utf-8
+End:


More information about the Python-checkins mailing list