Abstract
This PEP proposes changes to the introspection API for types that
makes them look more like classes, and their instances more like
class instances. For example, type(x) will be equivalent to
x.__class__ for most built-in types. When C is x.__class__,
x.meth(a) will generally be equivalent to C.meth(x, a), and
C.__dict__ contains x's methods and other attributes.
This PEP also introduces a new approach to specifying attributes,
using attribute descriptors, or descriptors for short.
Descriptors unify and generalize several different common
mechanisms used for describing attributes: a descriptor can
describe a method, a typed field in the object structure, or a
generalized attribute represented by getter and setter functions.
Based on the generalized descriptor API, this PEP also introduces
a way to declare class methods and static methods.
[Editor's note: the ideas described in this PEP have been incorporated
into Python. The PEP no longer accurately describes the implementation.]
Introduction
One of Python's oldest language warts is the difference between
classes and types. For example, you can't directly subclass the
dictionary type, and the introspection interface for finding out
what methods and instance variables an object has is different for
types and for classes.
Healing the class/type split is a big effort, because it affects
many aspects of how Python is implemented. This PEP concerns
itself with making the introspection API for types look the same
as that for classes. Other PEPs will propose making classes look
more like types, and subclassing from built-in types; these topics
are not on the table for this PEP.
Introspection APIs
Introspection concerns itself with finding out what attributes an
object has. Python's very general getattr/setattr API makes it
impossible to guarantee that there always is a way to get a list
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 Jim Fulton'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 assumptions here
are:
- attributes defined in the instance dict override attributes
defined by the object's class;
- attributes defined in a derived class override attributes
defined in a base class;
- attributes in an earlier base class (meaning occurring earlier
in __bases__) override attributes in a later base class.
(The last two rules together are often summarized as the
left-to-right, depth-first rule for attribute search. This is the
classic Python attribute lookup rule. Note that PEP 253 will
propose to change the attribute lookup order, and if accepted,
this PEP will follow suit.)
The type-based introspection API is supported in one form or