summaryrefslogtreecommitdiff
path: root/pypers/meta/metatype.html
diff options
context:
space:
mode:
Diffstat (limited to 'pypers/meta/metatype.html')
-rwxr-xr-xpypers/meta/metatype.html197
1 files changed, 0 insertions, 197 deletions
diff --git a/pypers/meta/metatype.html b/pypers/meta/metatype.html
deleted file mode 100755
index f83b6bb..0000000
--- a/pypers/meta/metatype.html
+++ /dev/null
@@ -1,197 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="Docutils 0.2.8: http://docutils.sourceforge.net/" />
-<title>SOLVING THE METACLASS CONFLICT</title>
-<link rel="stylesheet" href="default.css" type="text/css" />
-</head>
-<body>
-<div class="document" id="solving-the-metaclass-conflict">
-<h1 class="title">SOLVING THE METACLASS CONFLICT</h1>
-<div class="section" id="summary">
-<h1><a name="summary">Summary:</a></h1>
-<p>Any serious user of metaclasses has been bitten at least once by the
-infamous metaclass/metatype conflict. Here I give a general recipe to
-solve the problem, as well as some theory and some examples.</p>
-<blockquote>
-<pre class="literal-block">
-#&lt;noconflict.py&gt;
-
-def _generatemetaclass(bases,metas):
- &quot;&quot;&quot;Internal function called by inferred. 'bases' is tuple of base classes
- and 'metas' a tuple of metaclasses.&quot;&quot;&quot;
-
- metas=[m for m in metas if m is not type]
- trivial=lambda m: m is type or m in metas
- metabases=metas+[mb for mb in map(type,bases) if not trivial(mb)]
- metaname=&quot;_&quot;+''.join([m.__name__ for m in metabases])
- if not metabases: # trivial metabase
- return type
- elif len(metabases)==1: # single metabase
- return metabases[0]
- else: # multiple metabases
- # creates new metaclass,shift possible conflict to meta-metaclasses
- return type(metaname,tuple(metabases),{})
-
-def memoize(f):
- &quot;&quot;&quot;This closure remembers all f invocations&quot;&quot;&quot;
- argskw,result = [],[]
- def _(*args,**kw):
- akw=args,kw
- try: # returns a previously stored result
- return result[argskw.index(akw)]
- except ValueError: # there is no previously stored result
- argskw.append(akw) # update argskw
- result.append(f(*args,**kw)) # update result
- return result[-1] # return the new result
- _.argskw=argskw #makes the argskw list accessible outside
- _.result=result #makes the result list accessible outside
- return _
-
-_generatemetaclass=memoize(_generatemetaclass)
-
-def inferred(*metas):
- &quot;&quot;&quot;Class factory avoiding metatype conflicts: if the base classes have
- metaclasses conflicting within themselves or with the given metaclass,
- it automatically generates a compatible metaclass and instantiate the
- inferred class from it.&quot;&quot;&quot;
- return lambda n,b,d: _generatemetaclass(b,metas or (type,))(n,b,d)
-
-#&lt;/noconflict.py&gt;
-</pre>
-</blockquote>
-</div>
-<div class="section" id="discussion">
-<h1><a name="discussion">Discussion</a></h1>
-<p>I think that not too many programmers are familiar with metaclasses and
-metatype conflicts, therefore let me be pedagogical ;)</p>
-<p>The simplest case where a metatype conflict happens is the following.
-Consider a class <tt class="literal"><span class="pre">A</span></tt> with metaclass <tt class="literal"><span class="pre">M_A</span></tt> and a class <tt class="literal"><span class="pre">B</span></tt> with
-an independent metaclass <tt class="literal"><span class="pre">M_B</span></tt>; suppose we derive <tt class="literal"><span class="pre">C</span></tt> from <tt class="literal"><span class="pre">A</span></tt>
-and <tt class="literal"><span class="pre">B</span></tt>. The question is: what is the metaclass of <tt class="literal"><span class="pre">C</span></tt> ?
-Is it <tt class="literal"><span class="pre">M_A</span></tt> or <tt class="literal"><span class="pre">M_B</span></tt> ?</p>
-<blockquote>
-<pre class="doctest-block">
-&gt;&gt;&gt; class M_A(type):
-... pass
-&gt;&gt;&gt; class M_B(type):
-... pass
-&gt;&gt;&gt; class A(object):
-... __metaclass__=M_A
-&gt;&gt;&gt; class B(object):
-... __metaclass__=M_B
-&gt;&gt;&gt; class C(A,B):
-... pass
-Traceback (most recent call last):
- File &quot;&lt;stdin&gt;&quot;, line 1, in ?
-TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
-</pre>
-</blockquote>
-<p>The correct answer (see the book &quot;Putting metaclasses to work&quot; for a
-thought discussion) is <tt class="literal"><span class="pre">M_C</span></tt>, where <tt class="literal"><span class="pre">M_C</span></tt> is a metaclass that inherits
-from <tt class="literal"><span class="pre">M_A</span></tt> and <tt class="literal"><span class="pre">M_B</span></tt>, as in the following graph, where instantiation
-is denoted by colon lines:</p>
-<blockquote>
-<pre class="literal-block">
-M_A M_B
- : \ / :
- : \ / :
- A M_C B
- \ : /
- \ : /
- C
-</pre>
-</blockquote>
-<p>However, Python is not that magic, and it does not automatically create
-<tt class="literal"><span class="pre">M_C</span></tt>. Instead, it raises a <tt class="literal"><span class="pre">TypeError</span></tt>, warning the programmer of
-the possible confusion. The metatype conflict can be avoided
-by assegning the correct metaclass to <tt class="literal"><span class="pre">C</span></tt> by hand:</p>
-<blockquote>
-<pre class="doctest-block">
-&gt;&gt;&gt; class M_AM_B(M_A,M_B): pass
-...
-&gt;&gt;&gt; class C(A,B):
-... __metaclass__=M_AM_B
-&gt;&gt;&gt; C,type(C)
-(&lt;class 'C'&gt;, &lt;class 'M_AM_B'&gt;)
-</pre>
-</blockquote>
-<p>In general, a class <tt class="literal"><span class="pre">A(B,</span> <span class="pre">C,</span> <span class="pre">D</span> <span class="pre">,</span> <span class="pre">...)</span></tt> can be generated without conflicts
-only if <tt class="literal"><span class="pre">type(A)</span></tt> is a subclass of each of <tt class="literal"><span class="pre">type(B),</span> <span class="pre">type(C),</span> <span class="pre">...</span></tt></p>
-<p>It is possible to automatically avoid conflicts, by defining a smart
-class factory that generates the correct metaclass by looking at the
-metaclasses of the base classes. This is done via the <tt class="literal"><span class="pre">inferred</span></tt>
-class factory, wich internally invokes the <tt class="literal"><span class="pre">_generatemetaclass</span></tt>
-function. When <tt class="literal"><span class="pre">_generatemetaclass</span></tt> is invoked with the same bases and
-the same metaclasses it should return the same metaclass. This is done by
-keeping a list of the generated metaclasses thanks to the <tt class="literal"><span class="pre">with_memory</span></tt>
-closure. Now, when <tt class="literal"><span class="pre">_generatemetaclass</span></tt> is invoked with the same arguments
-it returns the same metaclass.</p>
-<blockquote>
-<pre class="doctest-block">
-&gt;&gt;&gt; import sys; sys.path.append('.') # for doctest purposes
-&gt;&gt;&gt; from noconflict import inferred
-&gt;&gt;&gt; class C(A,B):
-... __metaclass__=inferred()
-&gt;&gt;&gt; C
-&lt;class 'C'&gt;
-&gt;&gt;&gt; type(C) # automatically generated metaclass
-&lt;class 'noconflict._M_AM_B'&gt;
-</pre>
-<pre class="doctest-block">
-&gt;&gt;&gt; class M_A(type): pass
-...
-&gt;&gt;&gt; class M_B(type): pass
-...
-&gt;&gt;&gt; class A: __metaclass__=M_A
-...
-&gt;&gt;&gt; class B: __metaclass__=M_B
-...
-&gt;&gt;&gt; class E(A,B):
-... __metaclass__=inferred()
-&gt;&gt;&gt; type(E)
-&lt;class 'noconflict._M_AM_B'&gt;
-&gt;&gt;&gt; class F(A,B):
-... __metaclass__=inferred()
-&gt;&gt;&gt; type(F)
-&lt;class 'noconflict._M_AM_B'&gt;
-&gt;&gt;&gt; type(E) is type(F)
-True
-</pre>
-</blockquote>
-<p>Another example where <tt class="literal"><span class="pre">inferred()</span></tt> can solve the conflict is the
-following:</p>
-<blockquote>
-<pre class="doctest-block">
-&gt;&gt;&gt; class D(A):
-... __metaclass__=M_B
-Traceback (most recent call last):
- File &quot;&lt;string&gt;&quot;, line 1, in ?
-TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
-</pre>
-</blockquote>
-<p>Here the problem is that since <tt class="literal"><span class="pre">D</span></tt> inherits from <tt class="literal"><span class="pre">A</span></tt>, its metaclass
-must inherit from <tt class="literal"><span class="pre">M_A</span></tt> and cannot be <tt class="literal"><span class="pre">M_B</span></tt>.</p>
-<p><tt class="literal"><span class="pre">inferred</span></tt> solves the problem by automatically inheriting both from
-<tt class="literal"><span class="pre">M_B</span></tt> and <tt class="literal"><span class="pre">M_A</span></tt>:</p>
-<blockquote>
-<pre class="doctest-block">
-&gt;&gt;&gt; class D(A):
-... __metaclass__=inferred(M_B)
-&gt;&gt;&gt; type(D)
-&lt;class 'noconflict._M_BM_A'&gt;
-</pre>
-</blockquote>
-<p>Note: these examples here have been checked with doctest on Python 2.3b1.</p>
-</div>
-</div>
-<hr class="footer"/>
-<div class="footer">
-<a class="reference" href="metatype.txt">View document source</a>.
-Generated on: 2003-06-06 22:08 UTC.
-Generated by <a class="reference" href="http://docutils.sourceforge.net/">Docutils</a> from <a class="reference" href="http://docutils.sourceforge.net/rst.html">reStructuredText</a> source.
-</div>
-</body>
-</html>