Quick merge of Barry's feedback of four weeks ago. ;-(

This commit is contained in:
Guido van Rossum 2001-09-08 12:42:48 +00:00
parent aaebded223
commit 449eed85f9
1 changed files with 61 additions and 38 deletions

View File

@ -93,7 +93,7 @@ Introspection APIs
f.__members__ lists the names of f's statically defined f.__members__ lists the names of f's statically defined
attributes). attributes).
Some caution must be exercised: some objects don't list theire Some caution must be exercised: some objects don't list their
"intrinsic" attributes (like __dict__ and __doc__) in __members__, "intrinsic" attributes (like __dict__ and __doc__) in __members__,
while others do; sometimes attribute names occur both in while others do; sometimes attribute names occur both in
__members__ or __methods__ and as keys in __dict__, in which case __members__ or __methods__ and as keys in __dict__, in which case
@ -136,7 +136,10 @@ Specification of the class-based introspection API
(XXX static and dynamic are not great terms to use here, because (XXX static and dynamic are not great terms to use here, because
"static" attributes may actually behave quite dynamically, and "static" attributes may actually behave quite dynamically, and
because they have nothing to do with static class members in C++ because they have nothing to do with static class members in C++
or Java.) or Java. Barry suggests to use immutable and mutable instead, but
those words already have precise and different meanings in
slightly different contexts, so I think that would still be
confusing.)
Examples of dynamic attributes are instance variables of class Examples of dynamic attributes are instance variables of class
instances, module attributes, etc. Examples of static attributes instances, module attributes, etc. Examples of static attributes
@ -206,7 +209,7 @@ Specification of the class-based introspection API
descriptors; we'll explain these later. An unbound method is a descriptors; we'll explain these later. An unbound method is a
special case of an attribute descriptor. special case of an attribute descriptor.
Becase a meta-object is also a regular object, the items in a Because a meta-object is also a regular object, the items in a
meta-object's __dict__ correspond to attributes of the meta-object's __dict__ correspond to attributes of the
meta-object; however, some transformation may be applied, and meta-object; however, some transformation may be applied, and
bases (see below) may define additional dynamic attributes. In bases (see below) may define additional dynamic attributes. In
@ -223,20 +226,29 @@ Specification of the class-based introspection API
an empty sequence of bases. There must never be a cycle in the an empty sequence of bases. There must never be a cycle in the
relationship between meta-objects defined by __bases__ relationship between meta-objects defined by __bases__
attributes; in other words, the __bases__ attributes define an attributes; in other words, the __bases__ attributes define an
directed acyclic graph. (It is not necessarily a tree, since directed acyclic graph, with arcs pointing from derived
multiple classes can have the same base class.) The __dict__ meta-objects to their base meta-objects. (It is not
attributes of the meta-objects in the inheritance graph supply necessarily a tree, since multiple classes can have the same
attribute descriptors for the regular object whose __class__ is base class.) The __dict__ attributes of a meta-object in the
at the top of the inheritance graph. inheritance graph supply attribute descriptors for the regular
object whose __class__ attribute points to the root of the
inheritance tree (which is not the same as the root of the
inheritance hierarchy -- rather more the opposite, at the
bottom given how inheritance trees are typically drawn).
Descriptors are first searched in the dictionary of the root
meta-object, then in its bases, according to a precedence rule
(see the next paragraph).
5. Precedence rules 5. Precedence rules
When two meta-objects in the inheritance graph for a given When two meta-objects in the inheritance graph for a given
regular object both define an attribute descriptor with the regular object both define an attribute descriptor with the
same name, the left-to-right depth-first rule applies. (This same name, the search order is up to the meta-object. This
is the classic Python attribute lookup rule. Note that PEP 253 allows different meta-objects to define different search
will propose to change the attribute lookup order, and if orders. In particular, classic classes use the old
accepted, this PEP will follow suit.) left-to-right depth-first rule, while new-style classes use a
more advanced rule (see the section on method resolution order
in PEP 253).
When a dynamic attribute (one defined in a regular object's When a dynamic attribute (one defined in a regular object's
__dict__) has the same name as a static attribute (one defined __dict__) has the same name as a static attribute (one defined
@ -244,7 +256,10 @@ Specification of the class-based introspection API
object's __class__), the static attribute has precedence if it object's __class__), the static attribute has precedence if it
is a descriptor that defines a __set__ method (see below); is a descriptor that defines a __set__ method (see below);
otherwise (if there is no __set__ method) the dynamic attribute otherwise (if there is no __set__ method) the dynamic attribute
has precedence. has precedence. In other words, for data attributes (those
with a __set__ method), the static definition overrides the
dynamic definition, but for other attributes, dynamic overrides
static.
Rationale: we can't have a simple rule like "static overrides Rationale: we can't have a simple rule like "static overrides
dynamic" or "dynamic overrides static", because some static dynamic" or "dynamic overrides static", because some static
@ -325,27 +340,25 @@ Specification of the attribute descriptor API
C.meth.__objclass__ is C. C.meth.__objclass__ is C.
- __get__(): a function callable with one or two arguments that - __get__(): a function callable with one or two arguments that
retrieves the attribute value from an object. With one retrieves the attribute value from an object. This is also
argument, X, this either (for data attributes) retrieves the referred to as a "binding" operation, because it may return a
attribute value from X or (for method attributes) binds the "bound method" object in the case of method descriptors. The
attribute to X (returning some form of "bound" object that first argument, X, is the object from which the attribute must
receives an implied first argument of X when called). With two be retrieved or to which it must be bound. When X is None, the
arguments, X and T, T must be a meta-object that restricts the optional second argument, T, should be meta-object and the
type of X. X must either be an instance of T (in which the binding operation may return an *unbound* method restricted to
effect is the same as when T is omitted), or None. When X is instances of T. When both X and T are specified, X should be an
None, this should be a method descriptor, and the result is an instance of T. Exactly what is returned by the binding
*unbound* method restricted to objects whose type is (a operation depends on the semantics of the descriptor; for
descendent of) T. Such an unbound method is a descriptor example, static methods and class methods (see below) ignore the
itself. For methods, this is called a "binding" operation, even instance and bind to the type instead.
if X==None. Exactly what is returned by the binding operation
depends on the semantics of the descriptor; for example, static
methods and class methods (see below) ignore the instance and
bind to the type instead.
- __set__(): a function of two arguments that sets the attribute - __set__(): a function of two arguments that sets the attribute
value on the object. If the attribute is read-only, this method value on the object. If the attribute is read-only, this method
raises a TypeError exception. (Not an AttributeError!) may raise a TypeError or AttributeError exception (both are
Example: C.ivar.set(x, y) ~~ x.ivar = y. allowed, because both are historically found for undefined or
unsettable attributes). Example:
C.ivar.set(x, y) ~~ x.ivar = y.
Static methods and class methods Static methods and class methods
@ -377,6 +390,11 @@ Static methods and class methods
function objects would have created a bound method object for function objects would have created a bound method object for
'c.foo' and an unbound method object for 'C.foo'. 'c.foo' and an unbound method object for 'C.foo'.
(XXX Barry suggests to use "sharedmethod" instead of
"staticmethod", because the word statis is being overloaded in so
many ways already. But I'm not sure if shared conveys the right
meaning.)
Class methods use a similar pattern to declare methods that Class methods use a similar pattern to declare methods that
receive an implicit first argument that is the *class* for which receive an implicit first argument that is the *class* for which
they are invoked. This has no C++ or Java equivalent, and is not they are invoked. This has no C++ or Java equivalent, and is not
@ -431,10 +449,15 @@ Static methods and class methods
In this example, the call to C.foo() from E.foo() will see class C In this example, the call to C.foo() from E.foo() will see class C
as its first argument, not class E. This is to be expected, since as its first argument, not class E. This is to be expected, since
the call specifies the class C. But it stresses the difference the call specifies the class C. But it stresses the difference
between these class methods and methods defined in metaclasses between these class methods and methods defined in metaclasses,
(where an upcall to a metamethod would pass the target class as an where an upcall to a metamethod would pass the target class as an
explicit first argument). If you don't understand this, don't explicit first argument. (If you don't understand this, don't
worry, you're not alone. worry, you're not alone.) Note that calling cls.foo(y) would be a
mistake -- it would cause infinite recursion. Also note that you
can't specify an explicit 'cls' argument to a class method. If
you want this (e.g. the __new__ method in PEP 253 requires this),
use a static method with a class as its explicit first argument
instead.
C API C API
@ -567,9 +590,9 @@ C API
This requires a classification of descriptors as data and This requires a classification of descriptors as data and
nondata descriptors. The current implementation quite sensibly nondata descriptors. The current implementation quite sensibly
classifies member and getset descriptors as data (even if they classifies member and getset descriptors as data (even if they
are read-only!) and member descriptors as nondata. are read-only!) and method descriptors as nondata.
Non-descriptors (like function pointers or plain values) are Non-descriptors (like function pointers or plain values) are
also classified as non-data. also classified as non-data (!).
- This scheme has one drawback: in what I assume to be the most - This scheme has one drawback: in what I assume to be the most
common case, referencing an instance variable stored in the common case, referencing an instance variable stored in the