mirror of
https://github.com/kennethreitz/dive-into-python3.git
synced 2026-06-05 23:10:17 +00:00
522 lines
16 KiB
HTML
522 lines
16 KiB
HTML
<!DOCTYPE html>
|
||
<head>
|
||
<meta charset=utf-8>
|
||
<title>Special Method Names - Dive into Python 3</title>
|
||
<!--[if IE]><script src=html5.js></script><![endif]-->
|
||
<link rel=stylesheet type=text/css href=dip3.css>
|
||
<style>
|
||
h1:before{counter-increment:h1;content:"Appendix B. "}
|
||
h2:before{counter-increment:h2;content:"B." counter(h2) ". "}
|
||
h3:before{counter-increment:h3;content:"B." counter(h2) "." counter(h3) ". "}
|
||
tr + tr th:first-child{font:medium 'Arial Unicode MS',FreeSerif,OpenSymbol,'DejaVu Sans',sans-serif}
|
||
table{width:100%;border-collapse:collapse}
|
||
th,td{width:30%;padding:0 0.5em;border:1px solid #bbb}
|
||
th{text-align:left;vertical-align:baseline}
|
||
td{vertical-align:top}
|
||
th:first-child{width:10%;text-align:center}
|
||
th,td,td pre{margin:0}
|
||
td pre{padding:0;border:0}
|
||
</style>
|
||
<link rel=stylesheet type=text/css media='only screen and (max-device-width: 480px)' href=mobile.css>
|
||
</head>
|
||
<form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8> <input name=q size=25> <input type=submit name=sa value=Search></div></form>
|
||
<p>You are here: <a href=index.html>Home</a> <span>‣</span> <a href=table-of-contents.html#special-method-names>Dive Into Python 3</a> <span>‣</span>
|
||
<p id=level>Difficulty level: <span title=advanced>♦♦♦♦♦</span>
|
||
<h1>Special Method Names</h1>
|
||
<blockquote class=q>
|
||
<p><span>❝</span> FIXME <span>❞</span><br>— FIXME
|
||
</blockquote>
|
||
<p id=toc>
|
||
<h2 id=divingin>Diving in</h2>
|
||
<p class=f>FIXME
|
||
|
||
<h2 id=basics>Basics</h2>
|
||
|
||
<pre>
|
||
__init__ - covered in iterators.html
|
||
__repr__ - covered in ordereddict.py
|
||
__str__ - covered in fractions.py
|
||
__bytes__ (*)
|
||
__format__
|
||
</pre>
|
||
|
||
<h2 id=rich-comparisons>Rich Comparisons</h2>
|
||
|
||
<pre>
|
||
__lt__ - covered in fractions.py
|
||
__le__ - covered in fractions.py
|
||
__eq__ - covered in ordereddict.py, fractions.py
|
||
__ne__
|
||
__gt__ - covered in fractions.py
|
||
__ge__ - covered in fractions.py
|
||
__bool__ - covered in fractions.py
|
||
|
||
(__cmp__ is gone)
|
||
</pre>
|
||
|
||
<h2 id=custom-attributes>Custom Attributes</h2>
|
||
|
||
<pre>
|
||
__getattr__
|
||
__getattribute__
|
||
__setattr__
|
||
__delattr__
|
||
__dir__
|
||
</pre>
|
||
|
||
<h2 id=acts-like-function>Classes That Act Like Functions</h2>
|
||
|
||
<pre>
|
||
__call__
|
||
</pre>
|
||
|
||
<h2 id=acts-like-list>Classes That Act Like Sequences</h2>
|
||
|
||
<p>FIXME sequence intro
|
||
|
||
<table>
|
||
<tr><th>Notes
|
||
<th>You Want…
|
||
<th>So You Write…
|
||
<th>And Python Calls…
|
||
<tr><th>
|
||
<td>length of a sequence
|
||
<td><code>len(seq)</code>
|
||
<td><code>seq.__len__()</code>
|
||
<tr><th>
|
||
<td>whether a sequence contains a specific value
|
||
<td><code>x in seq</code>
|
||
<td><code>seq.__contains__(<var>x</var>)</code>
|
||
</table>
|
||
|
||
<!--
|
||
__len__
|
||
__contains__
|
||
-->
|
||
|
||
<h2 id=acts-like-dict>Classes That Act Like Dictionaries</h2>
|
||
|
||
<pre>
|
||
__getitem__
|
||
__setitem__ - covered in ordereddict.py
|
||
__delitem__ - covered in ordereddict.py
|
||
__missing__ (*)
|
||
</pre>
|
||
|
||
<h2 id=acts-like-iterator>Classes That Act Like Iterators</h2>
|
||
|
||
<!--
|
||
<tr><th>
|
||
<td>reversed sequence
|
||
<td><code>reversed(seq)</code>
|
||
<td><code>x.__reversed__()</code>
|
||
-->
|
||
<pre>
|
||
__iter__ (*) - covered in iterators.html
|
||
__next__ (*) - covered in iterators.html
|
||
__reversed__ - covered in ordereddict.py
|
||
</pre>
|
||
|
||
<h2 id=acts-like-number>Classes That Act Like Numbers</h2>
|
||
|
||
<p>Using the appropriate special methods, you can define your own classes that act like numbers. That is, you can add them, subtract them, and perform other mathematical operations on them. This is how <a href=advanced-classes.html#implementing-fractions>fractions are implemented</a> — the <code>Fraction</code> class implements these special methods, then you can do things like this:
|
||
|
||
<pre class=screen>
|
||
<samp class=p>>>> </samp><kbd>from fractions import Fraction</kbd>
|
||
<samp class=p>>>> </samp><kbd>x = Fraction(1, 3)</kbd>
|
||
<samp class=p>>>> </samp><kbd>x / 3</kbd>
|
||
<samp>Fraction(1, 9)</samp></pre>
|
||
|
||
<p>Here is the comprehensive list of special methods you need to implement a number-like class.
|
||
|
||
<table>
|
||
<tr><th>Notes
|
||
<th>You Want…
|
||
<th>So You Write…
|
||
<th>And Python Calls…
|
||
<tr><th>
|
||
<td>addition
|
||
<td><code>x + y</code>
|
||
<td><code>x.__add__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>subtraction
|
||
<td><code>x - y</code>
|
||
<td><code>x.__sub__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>multiplication
|
||
<td><code>x * y</code>
|
||
<td><code>x.__mul__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>division
|
||
<td><code>x / y</code>
|
||
<td><code>x.__truediv__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>floor division
|
||
<td><code>x // y</code>
|
||
<td><code>x.__floordiv__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>modulo (remainder)
|
||
<td><code>x % y</code>
|
||
<td><code>x.__mod__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>floor division <i class=baa>&</i> modulo
|
||
<td><code>divmod(x, y)</code>
|
||
<td><code>x.__divmod__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>raise to power
|
||
<td><code>x ** y</code>
|
||
<td><code>x.__pow__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>left bit-shift
|
||
<td><code>x << y</code>
|
||
<td><code>x.__lshift__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>right bit-shift
|
||
<td><code>x >> y</code>
|
||
<td><code>x.__rshift__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>and</code>
|
||
<td><code>x & y</code>
|
||
<td><code>x.__and__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>xor</code>
|
||
<td><code>x ^ y</code>
|
||
<td><code>x.__xor__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>or</code>
|
||
<td><code>x | y</code>
|
||
<td><code>x.__or__(<var>y</var>)</code>
|
||
</table>
|
||
|
||
<!--
|
||
__add__ - covered in fractions.py
|
||
__sub__
|
||
__mul__
|
||
__truediv__
|
||
__floordiv__ - covered in fractions.py
|
||
__mod__ - covered in fractions.py
|
||
__divmod__
|
||
__pow__ - covered in fractions.py
|
||
__lshift__
|
||
__rshift__
|
||
__and__
|
||
__xor__
|
||
__or__
|
||
-->
|
||
|
||
<p>That’s all well and good if <var>x</var> is an instance of a class that implements those methods. But what if it doesn’t implement one of them? Or worse, what if it implements it, but it can’t handle certain kinds of arguments? For example:
|
||
|
||
<pre class=screen>
|
||
<samp class=p>>>> </samp><kbd>from fractions import Fraction</kbd>
|
||
<samp class=p>>>> </samp><kbd>x = Fraction(1, 3)</kbd>
|
||
<samp class=p>>>> </samp><kbd>1 / x</kbd>
|
||
<samp>Fraction(3, 1)</samp></pre>
|
||
|
||
<p>This is <em>not</em> a case of taking a <code>Fraction</code> and dividing it by an integer (as in the previous example). That case was straightforward: <code>x / 3</code> calls <code>x.__truediv__(3)</code>, and the <code>__truediv__()</code> method of the <code>Fraction</code> class handles all the math. But integers don’t “know” how to do arithmetic operations with fractions. So why does this example work?
|
||
|
||
<p>The answer lies in a second set of arithmetic special methods with <i>reflected operands</i>. Given an arithmetic operation that takes two operands (<i>e.g.</i> <code>x / y</code>), there are two ways to go about it:
|
||
|
||
<ol>
|
||
<li>Tell <var>x</var> to divide itself by <var>y</var>, or
|
||
<li>Tell <var>y</var> to divide itself into <var>x</var>
|
||
</ol>
|
||
|
||
<p>The set of special methods above take the first approach: given <code>x / y</code>, they provide a way for <var>x</var> to say “I know how to divide myself by <var>y</var>.” The following set of special methods tackle the second approach: they provide a way for <var>y</var> to say “I know how to be the denominator and divide myself into <var>x</var>.”
|
||
|
||
<table>
|
||
<tr><th>Notes
|
||
<th>You Want…
|
||
<th>So You Write…
|
||
<th>And Python Calls…
|
||
<tr><th>
|
||
<td>addition
|
||
<td><code>x + y</code>
|
||
<td><code>y.__radd__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>subtraction
|
||
<td><code>x - y</code>
|
||
<td><code>y.__rsub__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>multiplication
|
||
<td><code>x * y</code>
|
||
<td><code>y.__rmul__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>division
|
||
<td><code>x / y</code>
|
||
<td><code>y.__rtruediv__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>floor division
|
||
<td><code>x // y</code>
|
||
<td><code>y.__rfloordiv__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>modulo (remainder)
|
||
<td><code>x % y</code>
|
||
<td><code>y.__rmod__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>floor division <i class=baa>&</i> modulo
|
||
<td><code>divmod(x, y)</code>
|
||
<td><code>y.__rdivmod__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>raise to power
|
||
<td><code>x ** y</code>
|
||
<td><code>y.__rpow__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>left bit-shift
|
||
<td><code>x << y</code>
|
||
<td><code>y.__rlshift__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>right bit-shift
|
||
<td><code>x >> y</code>
|
||
<td><code>y.__rrshift__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>and</code>
|
||
<td><code>x & y</code>
|
||
<td><code>y.__rand__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>xor</code>
|
||
<td><code>x ^ y</code>
|
||
<td><code>y.__rxor__(<var>x</var>)</code>
|
||
<tr><th>
|
||
<td>bitwise <code>or</code>
|
||
<td><code>x | y</code>
|
||
<td><code>y.__ror__(<var>x</var>)</code>
|
||
</table>
|
||
|
||
<!--
|
||
__radd__ - covered in fractions.py
|
||
__rsub__
|
||
__rmul__
|
||
__rtruediv__
|
||
__rfloordiv__ - covered in fractions.py
|
||
__rmod__ - covered in fractions.py
|
||
__rpow__ - covered in fractions.py
|
||
__rlshift__
|
||
__rrshift__
|
||
__rand__
|
||
__rxor__
|
||
__ror__
|
||
-->
|
||
|
||
<p>But wait! There’s more! If you’re doing “in-place” operations, like <code>x /= 3</code>, there are even more special methods you can define.
|
||
|
||
<table>
|
||
<tr><th>Notes
|
||
<th>You Want…
|
||
<th>So You Write…
|
||
<th>And Python Calls…
|
||
<tr><th>
|
||
<td>in-place addition
|
||
<td><code>x += y</code>
|
||
<td><code>x.__iadd__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place subtraction
|
||
<td><code>x -= y</code>
|
||
<td><code>x.__isub__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place multiplication
|
||
<td><code>x *= y</code>
|
||
<td><code>x.__imul__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place division
|
||
<td><code>x /= y</code>
|
||
<td><code>x.__itruediv__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place floor division
|
||
<td><code>x //= y</code>
|
||
<td><code>x.__ifloordiv__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place modulo
|
||
<td><code>x %= y</code>
|
||
<td><code>x.__imod__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place raise to power
|
||
<td><code>x **= y</code>
|
||
<td><code>x.__ipow__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place left bit-shift
|
||
<td><code>x <<= y</code>
|
||
<td><code>x.__ilshift__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place right bit-shift
|
||
<td><code>x >>= y</code>
|
||
<td><code>x.__irshift__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place bitwise <code>and</code>
|
||
<td><code>x &= y</code>
|
||
<td><code>x.__iand__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place bitwise <code>xor</code>
|
||
<td><code>x ^= y</code>
|
||
<td><code>x.__ixor__(<var>y</var>)</code>
|
||
<tr><th>
|
||
<td>in-place bitwise <code>or</code>
|
||
<td><code>x |= y</code>
|
||
<td><code>x.__ior__(<var>y</var>)</code>
|
||
</table>
|
||
|
||
<!--
|
||
__iadd__
|
||
__isub__
|
||
__imul__
|
||
__itruediv__
|
||
__ifloordiv__
|
||
__imod__
|
||
__ipow__
|
||
__ilshift__
|
||
__irshift__
|
||
__iand__
|
||
__ixor__
|
||
__ior__
|
||
-->
|
||
|
||
<p>Note: for the most part, the in-place operation methods are not required. If you don’t define an in-place method for a particular operation, Python will try the methods. For example, to execute the expression <code>x /= y</code>, Python will:
|
||
|
||
<ol>
|
||
<li>Try calling <code>x.__itruediv__(<var>y</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, we’re done.
|
||
<li>Try calling <code>x.__truediv__(<var>y</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, the old value of <var>x</var> is discarded and replaced with the return value, just as if you had done <code> x = x / y</code> instead.
|
||
<li>Try calling <code>y.__rtruediv__(<var>x</var>)</code>. If this method is defined and returns a value other than <code>NotImplemented</code>, the old value of <var>x</var> is discarded and replaced with the return value.
|
||
</ol>
|
||
|
||
<p>So you only need to define in-place methods like the <code>__itruediv__()</code> method if you want to do some special optimization for in-place operands. Otherwise Python will essentially reformulate the in-place operand to use a regular operand + a variable assignment.
|
||
|
||
<p>There are also a few “unary” mathematical operations you can perform on number-like objects by themselves.
|
||
|
||
<table>
|
||
<tr><th>Notes
|
||
<th>You Want…
|
||
<th>So You Write…
|
||
<th>And Python Calls…
|
||
<tr><th>
|
||
<td>negative number
|
||
<td><code>-x</code>
|
||
<td><code>x.__neg__()</code>
|
||
<tr><th>
|
||
<td>positive number
|
||
<td><code>+x</code>
|
||
<td><code>x.__pos__()</code>
|
||
<tr><th>
|
||
<td>absolute value
|
||
<td><code>abs(x)</code>
|
||
<td><code>x.__abs__()</code>
|
||
<tr><th>
|
||
<td>inverse
|
||
<td><code>~x</code>
|
||
<td><code>x.__invert__()</code>
|
||
<tr><th>
|
||
<td>complex number
|
||
<td><code>complex(x)</code>
|
||
<td><code>x.__complex__()</code>
|
||
<tr><th>
|
||
<td>integer
|
||
<td><code>int(x)</code>
|
||
<td><code>x.__int__()</code>
|
||
<tr><th>
|
||
<td>floating point number
|
||
<td><code>float(x)</code>
|
||
<td><code>x.__float__()</code>
|
||
<tr><th>
|
||
<td>number rounded to nearest integer
|
||
<td><code>round(x)</code>
|
||
<td><code>x.__round__()</code>
|
||
<tr><th>
|
||
<td>number rounded to nearest <var>n</var> digits
|
||
<td><code>round(x, n)</code>
|
||
<td><code>x.__round__(n)</code>
|
||
<tr><th>
|
||
<td>smallest integer <code>>= x</code>
|
||
<td><code>math.ceil(x)</code>
|
||
<td><code>x.__ceil__()</code>
|
||
<tr><th>
|
||
<td>largest integer <code><= x</code>
|
||
<td><code>math.floor(x)</code>
|
||
<td><code>x.__floor__()</code>
|
||
<tr><th>
|
||
<td>truncate <code>x</code> to nearest integer toward <code>0</code>
|
||
<td><code>math.trunc(x)</code>
|
||
<td><code>x.__trunc__()</code>
|
||
<tr><th>
|
||
<td>??? FIXME what the hell is this?
|
||
<td><code>???</code>
|
||
<td><code>x.__index__()</code>
|
||
</table>
|
||
|
||
<!--
|
||
__neg__ - covered in fractions.py
|
||
__pos__ - covered in fractions.py
|
||
__abs__ - covered in fractions.py
|
||
__invert__
|
||
__complex__
|
||
__int__
|
||
__float__
|
||
__round__ - covered in fractions.py
|
||
__ceil__ (*) - covered in fractions.py
|
||
__floor__ (*) - covered in fractions.py
|
||
__trunc__ (*) - covered in fractions.py
|
||
__index__
|
||
-->
|
||
|
||
<h2 id=pickle>Support For Pickling</h2>
|
||
|
||
<pre>
|
||
see http://docs.python.org/3.0/library/pickle.html:
|
||
|
||
__copy__ (*) - covered in fractions.py
|
||
__deepcopy__ (*) - covered in fractions.py
|
||
__getnewargs__ (*)
|
||
__getinitargs__ (*)
|
||
__getstate__ (*)
|
||
__setstate__ (*)
|
||
__reduce__ (*) - covered in ordereddict.py, fractions.py
|
||
__reduce_ex__ (*)
|
||
</pre>
|
||
|
||
<h2 id=context-managers>Classes That Can Be Used in a <code>with</code> Block</h2>
|
||
|
||
<pre>
|
||
__enter__ see http://docs.python.org/3.0/library/stdtypes.html#typecontextmanager
|
||
__exit__
|
||
|
||
relevant excerpt from io.py:
|
||
|
||
def __enter__(self) -> "IOBase": # That's a forward reference
|
||
"""Context management protocol. Returns self."""
|
||
self._checkClosed()
|
||
return self
|
||
|
||
def __exit__(self, *args) -> None:
|
||
"""Context management protocol. Calls close()"""
|
||
self.close()
|
||
|
||
relevant excerpt from http://www.python.org/doc/3.0/reference/datamodel.html#with-statement-context-managers
|
||
|
||
object.__enter__(self)
|
||
Enter the runtime context related to this object. The with statement will bind this method’s return value to the target(s) specified in the as clause of the statement, if any.
|
||
object.__exit__(self, exc_type, exc_value, traceback)
|
||
Exit the runtime context related to this object. The parameters describe the exception that caused the context to be exited. If the context was exited without an exception, all three arguments will be None.
|
||
|
||
If an exception is supplied, and the method wishes to suppress the exception (i.e., prevent it from being propagated), it should return a true value. Otherwise, the exception will be processed normally upon exit from this method.
|
||
|
||
Note that __exit__() methods should not reraise the passed-in exception; this is the caller’s responsibility.
|
||
|
||
</pre>
|
||
|
||
<h2 id=esoterica>Really Esoteric Stuff</h2>
|
||
|
||
<pre>
|
||
__new__ - covered in fractions.py
|
||
__del__
|
||
__slots__
|
||
__hash__ - covered in fractions.py
|
||
__get__
|
||
__set__
|
||
__delete__
|
||
__subclasshook__ (*) see http://docs.python.org/3.0/library/abc.html
|
||
__instancecheck__ (*) see http://www.ibm.com/developerworks/linux/library/l-python3-2/
|
||
__subclasscheck__ (*)
|
||
</pre>
|
||
|
||
<p class=nav><a rel=prev href=porting-code-to-python-3-with-2to3.html title="back to “Porting code to Python 3 with 2to3”"><span>☜</span></a> <a rel=next class=todo><span>☞</span></a>
|
||
<p class=c>© 2001–9 <a href=about.html>Mark Pilgrim</a>
|
||
<script src=jquery.js></script>
|
||
<script src=dip3.js></script>
|