From c085851dde9c40d5a9dba8f6b1232b4ddeed44a8 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Sun, 18 Sep 2022 23:08:38 -0700 Subject: [PATCH 1/8] Fix some formatting in faq/design.rst --- Doc/faq/design.rst | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 9da1d01abd6f51..5e48b013785919 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -62,7 +62,7 @@ and think it is a bug in Python. It's not. This has little to do with Python, and much more to do with how the underlying platform handles floating-point numbers. -The :class:`float` type in CPython uses a C ``double`` for storage. A +The :class:`float` type in CPython uses a C :c:type:`double` for storage. A :class:`float` object's value is stored in binary floating-point with a fixed precision (typically 53 bits) and Python uses C operations, which in turn rely on the hardware implementation in the processor, to perform floating-point @@ -232,7 +232,7 @@ Similar methods exist for bytes and bytearray objects. How fast are exceptions? ------------------------ -A try/except block is extremely efficient if no exceptions are raised. Actually +A ``try/except`` block is extremely efficient if no exceptions are raised. Actually catching an exception is expensive. In versions of Python prior to 2.0 it was common to use this idiom:: @@ -352,7 +352,7 @@ will probably run out of file descriptors:: c = f.read(1) Indeed, using CPython's reference counting and destructor scheme, each new -assignment to *f* closes the previous file. With a traditional GC, however, +assignment to ``f`` closes the previous file. With a traditional GC, however, those file objects will only get collected (and closed) at varying and possibly long intervals. @@ -376,10 +376,10 @@ Python to work with it.) Traditional GC also becomes a problem when Python is embedded into other applications. While in a standalone Python it's fine to replace the standard -malloc() and free() with versions provided by the GC library, an application -embedding Python may want to have its *own* substitute for malloc() and free(), +``malloc()`` and ``free()`` with versions provided by the GC library, an application +embedding Python may want to have its *own* substitute for ``malloc()`` and ``free()``, and may not want Python's. Right now, CPython works with anything that -implements malloc() and free() properly. +implements ``malloc()`` and ``free()`` properly. Why isn't all memory freed when CPython exits? @@ -401,7 +401,7 @@ Why are there separate tuple and list data types? Lists and tuples, while similar in many respects, are generally used in fundamentally different ways. Tuples can be thought of as being similar to -Pascal records or C structs; they're small collections of related data which may +Pascal ``records`` or C ``structs``; they're small collections of related data which may be of different types which are operated on as a group. For example, a Cartesian coordinate is appropriately represented as a tuple of two or three numbers. @@ -444,12 +444,12 @@ far) under most circumstances, and the implementation is simpler. Dictionaries work by computing a hash code for each key stored in the dictionary using the :func:`hash` built-in function. The hash code varies widely depending -on the key and a per-process seed; for example, "Python" could hash to --539294296 while "python", a string that differs by a single bit, could hash -to 1142331976. The hash code is then used to calculate a location in an +on the key and a per-process seed; for example, ``Python`` could hash to +``-539294296`` while ``python``, a string that differs by a single bit, could hash +to ``1142331976``. The hash code is then used to calculate a location in an internal array where the value will be stored. Assuming that you're storing keys that all have different hash values, this means that dictionaries take -constant time -- O(1), in Big-O notation -- to retrieve a key. +constant time -- ``O(1)``, in Big-O notation -- to retrieve a key. Why must dictionary keys be immutable? @@ -528,7 +528,7 @@ is True``) then ``hash(o1) == hash(o2)`` (ie, ``o1.__hash__() == o2.__hash__()`` regardless of whether the object is in a dictionary or not. If you fail to meet these restrictions dictionaries and other hash based structures will misbehave. -In the case of ListWrapper, whenever the wrapper object is in a dictionary the +In the case of ``ListWrapper``, whenever the wrapper object is in a dictionary the wrapped list must not change to avoid anomalies. Don't do this unless you are prepared to think hard about the requirements and the consequences of not meeting them correctly. Consider yourself warned. @@ -599,14 +599,14 @@ Why is there no goto? In the 1970s people realized that unrestricted goto could lead to messy "spaghetti" code that was hard to understand and revise. In a high-level language, it is also unneeded as long as there -are ways to branch (in Python, with ``if`` statements and ``or``, -``and``, and ``if-else`` expressions) and loop (with ``while`` -and ``for`` statements, possibly containing ``continue`` and ``break``). +are ways to branch (in Python, with :keyword:`if` statements and :keyword:`or`, +:keyword:`and`, and ``if-else`` expressions) and loop (with :keyword:`while` +and :keyword:`for` statements, possibly containing :keyword:`continue` and :keyword:`break`). One can also use exceptions to provide a "structured goto" that works even across function calls. Many feel that exceptions can conveniently emulate all -reasonable uses of the "go" or "goto" constructs of C, Fortran, and other +reasonable uses of the ``go`` or ``goto`` constructs of C, Fortran, and other languages. For example:: class label(Exception): pass # declare a label @@ -620,7 +620,7 @@ languages. For example:: ... This doesn't allow you to jump into the middle of a loop, but that's usually -considered an abuse of goto anyway. Use sparingly. +considered an abuse of ``goto`` anyway. Use sparingly. Why can't raw strings (r-strings) end with a backslash? @@ -652,7 +652,7 @@ If you're trying to build a pathname for a DOS command, try e.g. one of :: Why doesn't Python have a "with" statement for attribute assignments? --------------------------------------------------------------------- -Python has a 'with' statement that wraps the execution of a block, calling code +Python has a :keyword:`with` statement that wraps the execution of a block, calling code on the entrance and exit from the block. Some languages have a construct that looks like this:: @@ -679,13 +679,13 @@ For instance, take the following incomplete snippet:: with a: print(x) -The snippet assumes that "a" must have a member attribute called "x". However, +The snippet assumes that ``a`` must have a member attribute called ``x``. However, there is nothing in Python that tells the interpreter this. What should happen -if "a" is, let us say, an integer? If there is a global variable named "x", -will it be used inside the with block? As you see, the dynamic nature of Python +if ``a`` is, let us say, an integer? If there is a global variable named ``x``, +will it be used inside the :keyword:`with` block? As you see, the dynamic nature of Python makes such choices much harder. -The primary benefit of "with" and similar language features (reduction of code +The primary benefit of :keyword:`with` and similar language features (reduction of code volume) can, however, easily be achieved in Python by assignment. Instead of:: function(args).mydict[index][index].a = 21 @@ -710,7 +710,7 @@ Why don't generators support the with statement? For technical reasons, a generator used directly as a context manager would not work correctly. When, as is most common, a generator is used as an iterator run to completion, no closing is needed. When it is, wrap -it as "contextlib.closing(generator)" in the 'with' statement. +it as ``contextlib.closing(generator)`` in the :keyword:`with` statement. Why are colons required for the if/while/def/class statements? From c300f881f357f27f12591f0fbcfde06fcb04ecd7 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Mon, 19 Sep 2022 02:50:59 -0700 Subject: [PATCH 2/8] Use links instead of literal --- Doc/faq/design.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 5e48b013785919..37392204102ec6 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -600,7 +600,7 @@ In the 1970s people realized that unrestricted goto could lead to messy "spaghetti" code that was hard to understand and revise. In a high-level language, it is also unneeded as long as there are ways to branch (in Python, with :keyword:`if` statements and :keyword:`or`, -:keyword:`and`, and ``if-else`` expressions) and loop (with :keyword:`while` +:keyword:`and`, and :keyword:`if-else ` expressions) and loop (with :keyword:`while` and :keyword:`for` statements, possibly containing :keyword:`continue` and :keyword:`break`). One can also use exceptions to provide a "structured goto" @@ -710,7 +710,7 @@ Why don't generators support the with statement? For technical reasons, a generator used directly as a context manager would not work correctly. When, as is most common, a generator is used as an iterator run to completion, no closing is needed. When it is, wrap -it as ``contextlib.closing(generator)`` in the :keyword:`with` statement. +it as :func:`contextlib.closing(generator) ` in the :keyword:`with` statement. Why are colons required for the if/while/def/class statements? From a96893aae200201f184f1b4c195e35a6c68222eb Mon Sep 17 00:00:00 2001 From: Stanley <46876382+slateny@users.noreply.github.com> Date: Mon, 19 Sep 2022 02:51:56 -0700 Subject: [PATCH 3/8] Add back quotes Co-authored-by: Ezio Melotti --- Doc/faq/design.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 37392204102ec6..373fde983582aa 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -444,8 +444,8 @@ far) under most circumstances, and the implementation is simpler. Dictionaries work by computing a hash code for each key stored in the dictionary using the :func:`hash` built-in function. The hash code varies widely depending -on the key and a per-process seed; for example, ``Python`` could hash to -``-539294296`` while ``python``, a string that differs by a single bit, could hash +on the key and a per-process seed; for example, ``'Python'`` could hash to +``-539294296`` while ``'python'``, a string that differs by a single bit, could hash to ``1142331976``. The hash code is then used to calculate a location in an internal array where the value will be stored. Assuming that you're storing keys that all have different hash values, this means that dictionaries take From a7542bae13bca7b8baf64969e80e411f65291175 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Tue, 20 Sep 2022 20:46:11 -0700 Subject: [PATCH 4/8] Add more proper refs --- Doc/faq/design.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 373fde983582aa..48798f060d7688 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -129,7 +129,7 @@ reference or call the method from a particular class. In C++, if you want to use a method from a base class which is overridden in a derived class, you have to use the ``::`` operator -- in Python you can write ``baseclass.methodname(self, )``. This is particularly useful -for :meth:`__init__` methods, and in general in cases where a derived class +for :meth:`~object.__init__` methods, and in general in cases where a derived class method wants to extend the base class method of the same name and thus has to call the base class method somehow. @@ -232,7 +232,8 @@ Similar methods exist for bytes and bytearray objects. How fast are exceptions? ------------------------ -A ``try/except`` block is extremely efficient if no exceptions are raised. Actually +A :keyword:`try`/:keyword:`except` block is extremely efficient if no exceptions +are raised. Actually catching an exception is expensive. In versions of Python prior to 2.0 it was common to use this idiom:: @@ -408,7 +409,8 @@ numbers. Lists, on the other hand, are more like arrays in other languages. They tend to hold a varying number of objects all of which have the same type and which are -operated on one-by-one. For example, ``os.listdir('.')`` returns a list of +operated on one-by-one. For example, :func:`os.listdir('.') ` +returns a list of strings representing the files in the current directory. Functions which operate on this output would generally not break if you added another file or two to the directory. @@ -497,7 +499,8 @@ Some unacceptable solutions that have been proposed: There is a trick to get around this if you need to, but use it at your own risk: You can wrap a mutable structure inside a class instance which has both a -:meth:`__eq__` and a :meth:`__hash__` method. You must then make sure that the +:meth:`~object.__eq__` and a :meth:`~object.__hash__` method. +You must then make sure that the hash value for all such wrapper objects that reside in a dictionary (or other hash based structure), remain fixed while the object is in the dictionary (or other structure). :: @@ -528,7 +531,7 @@ is True``) then ``hash(o1) == hash(o2)`` (ie, ``o1.__hash__() == o2.__hash__()`` regardless of whether the object is in a dictionary or not. If you fail to meet these restrictions dictionaries and other hash based structures will misbehave. -In the case of ``ListWrapper``, whenever the wrapper object is in a dictionary the +In the case of :class:`!ListWrapper`, whenever the wrapper object is in a dictionary the wrapped list must not change to avoid anomalies. Don't do this unless you are prepared to think hard about the requirements and the consequences of not meeting them correctly. Consider yourself warned. From 2d6870740429c2118f3fd2c3ef1d233cb1cdc4fe Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Tue, 20 Sep 2022 23:19:14 -0700 Subject: [PATCH 5/8] Add formatting for walrus operator --- Doc/faq/design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 48798f060d7688..81ddaed339dbcf 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -155,7 +155,7 @@ Why can't I use an assignment in an expression? Starting in Python 3.8, you can! -Assignment expressions using the walrus operator `:=` assign a variable in an +Assignment expressions using the walrus operator ``:=`` assign a variable in an expression:: while chunk := fp.read(200): From 399564cd153d582f4f184a067839e4506e09ff15 Mon Sep 17 00:00:00 2001 From: slateny <46876382+slateny@users.noreply.github.com> Date: Thu, 22 Sep 2022 02:10:46 -0700 Subject: [PATCH 6/8] Use list.append instead of append, if-else -> if/else --- Doc/faq/design.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 81ddaed339dbcf..0161246a06768d 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -584,9 +584,9 @@ exhaustive test suites that exercise every line of code in a module. An appropriate testing discipline can help build large complex applications in Python as well as having interface specifications would. In fact, it can be better because an interface specification cannot test certain properties of a -program. For example, the :meth:`append` method is expected to add new elements +program. For example, the :meth:`list.append` method is expected to add new elements to the end of some internal list; an interface specification cannot test that -your :meth:`append` implementation will actually do this correctly, but it's +your :meth:`list.append` implementation will actually do this correctly, but it's trivial to check this property in a test suite. Writing test suites is very helpful, and you might want to design your code to @@ -603,7 +603,7 @@ In the 1970s people realized that unrestricted goto could lead to messy "spaghetti" code that was hard to understand and revise. In a high-level language, it is also unneeded as long as there are ways to branch (in Python, with :keyword:`if` statements and :keyword:`or`, -:keyword:`and`, and :keyword:`if-else ` expressions) and loop (with :keyword:`while` +:keyword:`and`, and :keyword:`if`/:keyword:`else` expressions) and loop (with :keyword:`while` and :keyword:`for` statements, possibly containing :keyword:`continue` and :keyword:`break`). One can also use exceptions to provide a "structured goto" From e110dd13f361c5e8a5d764b2fa9af74b23f97b48 Mon Sep 17 00:00:00 2001 From: Stanley <46876382+slateny@users.noreply.github.com> Date: Thu, 22 Sep 2022 02:11:18 -0700 Subject: [PATCH 7/8] Wrap long line Co-authored-by: Ezio Melotti --- Doc/faq/design.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 0161246a06768d..05a5c90fb5856c 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -713,7 +713,8 @@ Why don't generators support the with statement? For technical reasons, a generator used directly as a context manager would not work correctly. When, as is most common, a generator is used as an iterator run to completion, no closing is needed. When it is, wrap -it as :func:`contextlib.closing(generator) ` in the :keyword:`with` statement. +it as :func:`contextlib.closing(generator) ` +in the :keyword:`with` statement. Why are colons required for the if/while/def/class statements? From ce33989449e1a92723fbd7a0d11341b616c53d99 Mon Sep 17 00:00:00 2001 From: Stanley <46876382+slateny@users.noreply.github.com> Date: Thu, 22 Sep 2022 19:31:06 -0700 Subject: [PATCH 8/8] Remove literal from big-O Co-authored-by: C.A.M. Gerlach --- Doc/faq/design.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 05a5c90fb5856c..7ac908122c52a6 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -451,7 +451,7 @@ on the key and a per-process seed; for example, ``'Python'`` could hash to to ``1142331976``. The hash code is then used to calculate a location in an internal array where the value will be stored. Assuming that you're storing keys that all have different hash values, this means that dictionaries take -constant time -- ``O(1)``, in Big-O notation -- to retrieve a key. +constant time -- O(1), in Big-O notation -- to retrieve a key. Why must dictionary keys be immutable?