summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-08-22 19:49:24 (GMT)
committerGitHub <noreply@github.com>2021-08-22 19:49:24 (GMT)
commit0627918f0b69a15aa16e4ccbb5d8eaae4f6a2caf (patch)
treed4175469734433f21465cd1a1f702ac3529b79f9
parent8e90f15ac88c66ddb7b084bb5780a126d35168af (diff)
downloadcpython-0627918f0b69a15aa16e4ccbb5d8eaae4f6a2caf.zip
cpython-0627918f0b69a15aa16e4ccbb5d8eaae4f6a2caf.tar.gz
cpython-0627918f0b69a15aa16e4ccbb5d8eaae4f6a2caf.tar.bz2
bpo-4442: Document use of __new__ for subclasses of immutable types (GH-27866)
(cherry picked from commit eec340ea3af27887fcaac4029ebdee99f3713bff) Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
-rw-r--r--Doc/faq/programming.rst49
1 files changed, 49 insertions, 0 deletions
diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
index af4b489..ef80808 100644
--- a/Doc/faq/programming.rst
+++ b/Doc/faq/programming.rst
@@ -1826,6 +1826,55 @@ For example, here is the implementation of
return True
return False
+
+How can a subclass control what data is stored in an immutable instance?
+------------------------------------------------------------------------
+
+When subclassing an immutable type, override the :meth:`__new__` method
+instead of the :meth:`__init__` method. The latter only runs *after* an
+instance is created, which is too late to alter data in an immutable
+instance.
+
+All of these immutable classes have a different signature than their
+parent class:
+
+.. testcode::
+
+ from datetime import date
+
+ class FirstOfMonthDate(date):
+ "Always choose the first day of the month"
+ def __new__(cls, year, month, day):
+ return super().__new__(cls, year, month, 1)
+
+ class NamedInt(int):
+ "Allow text names for some numbers"
+ xlat = {'zero': 0, 'one': 1, 'ten': 10}
+ def __new__(cls, value):
+ value = cls.xlat.get(value, value)
+ return super().__new__(cls, value)
+
+ class TitleStr(str):
+ "Convert str to name suitable for a URL path"
+ def __new__(cls, s):
+ s = s.lower().replace(' ', '-')
+ s = ''.join([c for c in s if c.isalnum() or c == '-'])
+ return super().__new__(cls, s)
+
+The classes can be used like this:
+
+.. doctest::
+
+ >>> FirstOfMonthDate(2012, 2, 14)
+ FirstOfMonthDate(2012, 2, 1)
+ >>> NamedInt('ten')
+ 10
+ >>> NamedInt(20)
+ 20
+ >>> TitleStr('Blog: Why Python Rocks')
+ 'blog-why-python-rocks'
+
+
How do I cache method calls?
----------------------------