From e0b2d7ac9aea548d0bee1cdabd5d7b1254a6569d Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Sat, 22 Sep 2001 06:10:55 +0000 Subject: [PATCH] Add a function to compute a class's method resolution order. This is easy for 2.2 new-style classes, but trickier for classic classes, and different approaches are needed "depending". The function will allow later code to treat all flavors of classes uniformly. --- Doc/lib/libinspect.tex | 10 +++++++++- Lib/inspect.py | 18 ++++++++++++++++++ Lib/test/test_inspect.py | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Doc/lib/libinspect.tex b/Doc/lib/libinspect.tex index e5ec9ca620..24a181a7a3 100644 --- a/Doc/lib/libinspect.tex +++ b/Doc/lib/libinspect.tex @@ -238,7 +238,7 @@ you can expect to find the following special attributes: \begin{funcdesc}{formatargspec}{args\optional{, varargs, varkw, defaults, argformat, varargsformat, varkwformat, defaultformat}} - + Format a pretty argument spec from the four values returned by \function{getargspec()}. The other four arguments are the corresponding optional formatting functions that are called to turn @@ -253,6 +253,14 @@ you can expect to find the following special attributes: names and values into strings. \end{funcdesc} +\begin{funcdesc}{getmro}{cls} + Return a tuple of class cls's base classes, including cls, in + method resolution order. No class appears more than once in this tuple. + Note that the method resolution order depends on cls's type. Unless a + very peculiar user-defined metatype is in use, cls will be the first + element of the tuple. +\end{funcdesc} + \subsection{The interpreter stack \label{inspect-stack}} diff --git a/Lib/inspect.py b/Lib/inspect.py index 1102c3b258..3febf1826d 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -163,6 +163,24 @@ def getmembers(object, predicate=None): results.sort() return results +# ----------------------------------------------------------- class helpers +def _searchbases(cls, accum): + # Simulate the "classic class" search order. + if cls in accum: + return + accum.append(cls) + for base in cls.__bases__: + _searchbases(base, accum) + +def getmro(cls): + "Return tuple of base classes (including cls) in method resolution order." + if hasattr(cls, "__mro__"): + return cls.__mro__ + else: + result = [] + _searchbases(cls, result) + return tuple(result) + # -------------------------------------------------- source code extraction def indentsize(line): """Return the indent size, in spaces, at the start of a line of text.""" diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 130fa8ef73..dbb66094e9 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -213,3 +213,23 @@ for fname in files_to_clean_up: os.unlink(fname) except: pass + +# Test classic-class method resolution order. +class A: pass +class B(A): pass +class C(A): pass +class D(B, C): pass + +expected = (D, B, A, C) +got = inspect.getmro(D) +test(expected == got, "expected %r mro, got %r", expected, got) + +# The same w/ new-class MRO. +class A(object): pass +class B(A): pass +class C(A): pass +class D(B, C): pass + +expected = (D, B, C, A, object) +got = inspect.getmro(D) +test(expected == got, "expected %r mro, got %r", expected, got) -- 2.40.0