Skip to content

Commit 85ff885

Browse files
committed
📝 Update module section
* Add module namespace * Add public API with __all__ * Rename circumference to perimeter
1 parent 149fda8 commit 85ff885

15 files changed

Lines changed: 171 additions & 63 deletions

File tree

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ Added
2525
Changed
2626
~~~~~~~
2727

28+
* 📝 Update module section
29+
30+
* Add module namespace
31+
* Add public API with __all__
32+
2833
* 📝 Update decorators
2934

3035
* Add functools.singledispatch

docs/appendix/checks.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -771,8 +771,8 @@ Checks
771771
:doc:`/oop/methods`
772772
-------------------
773773

774-
* Write a class method that is similar to :func:`circumferences`, but returns
775-
the total area of all circles.
774+
* Write a class method that is similar to :func:`perimeters`, but returns the
775+
total area of all circles.
776776

777777
.. code-block:: python
778778

docs/modules/index.rst

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ What is a module?
1111

1212
A module is a file that contains code. It defines a group of Python functions or
1313
other objects, and the name of the module is derived from the name of the file.
14+
1415
Modules usually contain Python source code [#]_, group related Python objects
1516
together and help to avoid naming conflicts. You can write a module called
1617
``mymodule`` for your programme that defines a function called ``my_func``. In
@@ -20,9 +21,25 @@ something different from your ``my_func`` function. Without modules, it would be
2021
impossible to use two different functions with the same name. With modules, you
2122
can refer to the functions ``mymodule.my_func`` and ``othermodule.my_func`` in
2223
your main programme. Using the module names ensures that the two ``my_func``
23-
functions are not confused, as Python uses so-called namespaces. A namespace is
24-
essentially a dictionary of names for the functions, classes, modules,
25-
:abbr:`etc. (et cetera)` available there.
24+
functions are not confused, as Python uses so-called :doc:`../oop/namespaces`. A
25+
namespace is essentially a :doc:`dictionary <../types/dicts>` of names for the
26+
functions, classes, modules, :abbr:`etc. (et cetera)` available there.
27+
28+
Namespaces are one honking great idea – let’s do more of those!
29+
30+
– `The Zen of Python <https://peps.python.org/pep-0020/>`_, by Tim Peters
31+
32+
.. code-block:: pycon
33+
34+
>>> import cmath, math
35+
>>> math.sin(34)
36+
0.5290826861200238
37+
>>> cmath.sin(34)
38+
(0.5290826861200238-0j)
39+
40+
.. warning::
41+
However, an import using wildcards negates this separation of namespaces:
42+
``import *`` carries over every name from one module to another.
2643

2744
Modules are also used to make Python itself more manageable. Most of Python’s
2845
standard functions are not integrated into the core of the language, but are
@@ -179,6 +196,77 @@ In addition, a help option ``-h`` or ``--help`` is automatically generated:
179196
-f FILENAME, --file FILENAME
180197
read data from the file
181198
199+
Declaring a public API with ``__all__``
200+
---------------------------------------
201+
202+
You can use ``__all__`` to expose a public API for your module, which determines
203+
what is imported when you use :samp:`from {MODULE} import *`. Let’s assume your
204+
module looks like this:
205+
206+
.. literalinclude:: perimeter.py
207+
:caption: perimeter.py
208+
209+
You can then use this module as follows:
210+
211+
.. code-block:: pycon
212+
213+
>>> from perimeter import *
214+
>>> circle_perimeter(3)
215+
9.42477796076938
216+
>>> square_perimeter(3)
217+
12
218+
>>> square_length(16)
219+
4.0
220+
221+
However, you cannot use the ``pi`` variable from the module:
222+
223+
.. code-block:: pycon
224+
225+
>>> pi
226+
Traceback (most recent call last):
227+
File "<python-input-1>", line 1, in <module>
228+
pi
229+
NameError: name 'pi' is not defined
230+
231+
Even with :py:func:`dir`, you’ll still only get those two functions from
232+
``__all__``:
233+
234+
.. code-block:: pycon
235+
236+
>>> dir()
237+
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'circle_perimeter', 'square_length', 'square_perimeter']
238+
239+
The advantage of this is that internal helper functions and variables are
240+
encapsulated and are not accidentally exported. Without ``__all__``, any name
241+
not beginning with an underscore would also have been imported, including ``pi``
242+
and the ``sqrt`` function, which we imported from :py:mod:`math`.
243+
244+
The :py:func:`help` function also reads from ``__all__`` and does not document
245+
everything in the module; the internal variable ``pi`` and ``sqrt``, which does
246+
not even originate from us, are not displayed:
247+
248+
.. code-block:: pycon
249+
250+
>>> import perimeter
251+
>>> help(perimeter)
252+
253+
.. code-block:: text
254+
255+
Help on module perimeter:
256+
257+
NAME
258+
perimeter
259+
260+
FUNCTIONS
261+
circle_perimeter(diameter)
262+
263+
square_length(area)
264+
265+
square_perimeter(length)
266+
267+
DATA
268+
__all__ = ['circle_perimeter', 'square_length', 'square_perimeter']
269+
182270
Checks
183271
------
184272

docs/modules/perimeter.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from math import sqrt
2+
3+
__all__ = ["circle_perimeter", "square_length", "square_perimeter"]
4+
pi = 3.141592653589793
5+
6+
7+
def circle_perimeter(diameter):
8+
return diameter * pi
9+
10+
11+
def square_perimeter(length):
12+
return length * 4
13+
14+
15+
def square_length(area):
16+
return sqrt(area)

docs/oop/circle.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ def __init__(self, diameter=1):
1717
self.diameter = diameter
1818
self.__class__.circles.append(self)
1919

20-
def circumference(self):
20+
def perimeter(self):
2121
return self.diameter * self.__class__.pi
2222

2323
@staticmethod
24-
def circumferences():
25-
"""Static method to sum all circle circumferences."""
24+
def perimeters():
25+
"""Static method to sum all circle perimeters."""
2626
csum = 0
2727
for c in Circle.circles:
28-
csum = csum + c.circumference()
28+
csum = csum + c.perimeter()
2929
return csum

docs/oop/circle_cm.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ def __init__(self, diameter=1):
1717
self.diameter = diameter
1818
self.__class__.circles.append(self)
1919

20-
def circumference(self):
20+
def perimeter(self):
2121
return self.diameter * self.__class__.pi
2222

2323
@classmethod
24-
def circumferences(cls):
25-
"""Class method to sum all circle circumferences."""
24+
def perimeters(cls):
25+
"""Class method to sum all circle perimeters."""
2626
csum = 0
2727
for c in cls.circles:
28-
csum = csum + c.circumference()
28+
csum = csum + c.perimeter()
2929
return csum

docs/oop/coherent.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ Python. I will now illustrate these basics in a coherent example:
5656
In the ``__init__`` method, the instance inserts itself into the
5757
``circles`` list.
5858
Lines 37 and 38
59-
``circumferences`` is a class method and takes the class itself
60-
(``cls``) as a :term:`parameter`.
59+
``perimeters`` is a class method and takes the class itself (``cls``) as
60+
a :term:`parameter`.
6161
Line 41
6262
uses the :term:`parameter` ``cls`` to access the class variable
6363
``circles``.
@@ -92,12 +92,12 @@ the ``Circle`` class, so it goes up the inheritance hierarchy and uses the
9292
>>> c2.diameter, c2.x, c2.y
9393
(2, 8, 10)
9494
95-
You can also call the class method ``circumferences()`` of the class ``Circle``,
95+
You can also call the class method ``perimeters()`` of the class ``Circle``,
9696
either through the class itself or through an instance:
9797

9898
.. code-block:: pycon
9999
100-
>>> form.Circle.circumferences()
100+
>>> form.Circle.perimeters()
101101
9.424769999999999
102-
>>> c2.circumferences()
102+
>>> c2.perimeters()
103103
9.424769999999999

docs/oop/form.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def __init__(self, length=1, x=0, y=0):
2020
super().__init__(x, y)
2121
self.length = length
2222

23-
def circumference(self):
23+
def perimeter(self):
2424
return 4 * self.length
2525

2626

@@ -35,13 +35,13 @@ def __init__(self, diameter=1, x=0, y=0):
3535
self.diameter = diameter
3636
self.__class__.circles.append(self)
3737

38-
def circumference(self):
38+
def perimeter(self):
3939
return self.diameter * self.__class__.pi
4040

4141
@classmethod
42-
def circumferences(cls):
43-
"""Class method to sum all circle circumferences."""
42+
def perimeters(cls):
43+
"""Class method to sum all circle perimeters."""
4444
csum = 0
4545
for c in cls.circles:
46-
csum = csum + c.circumference()
46+
csum = csum + c.perimeter()
4747
return csum

docs/oop/form_ns.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def length(self):
2828
def length(self, new_length):
2929
self.__length = new_length
3030

31-
def circumference(self):
31+
def perimeter(self):
3232
return 4 * self.__length
3333

3434

@@ -51,15 +51,15 @@ def diameter(self):
5151
def diameter(self, new_diameter):
5252
self.__diameter = new_diameter
5353

54-
def circumference(self):
54+
def perimeter(self):
5555
return self.diameter * self.__class__.pi
5656

5757
@classmethod
58-
def circumferences(cls):
59-
"""Class method to sum all circle circumferences."""
58+
def perimeters(cls):
59+
"""Class method to sum all circle perimeters."""
6060
csum = 0
6161
for c in cls.circles:
62-
csum = csum + c.circumference()
62+
csum = csum + c.perimeter()
6363
return csum
6464

6565
def namespaces(self):

docs/oop/form_pr.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def length(self):
2828
def length(self, new_length):
2929
self.__length = new_length
3030

31-
def circumference(self):
31+
def perimeter(self):
3232
return 4 * self.__length
3333

3434

@@ -51,13 +51,13 @@ def diameter(self):
5151
def diameter(self, new_diameter):
5252
self.__diameter = new_diameter
5353

54-
def circumference(self):
54+
def perimeter(self):
5555
return self.diameter * self.__class__.pi
5656

5757
@classmethod
58-
def circumferences(cls):
59-
"""Class method to sum all circle circumferences."""
58+
def perimeters(cls):
59+
"""Class method to sum all circle perimeters."""
6060
csum = 0
6161
for c in cls.circles:
62-
csum = csum + c.circumference()
62+
csum = csum + c.perimeter()
6363
return csum

0 commit comments

Comments
 (0)