python-mastery/Exercises/ex9_1.md

212 lines
4.2 KiB
Markdown
Raw Normal View History

2023-07-17 03:21:00 +02:00
\[ [Index](index.md) | [Exercise 8.6](ex8_6.md) | [Exercise 9.2](ex9_2.md) \]
# Exercise 9.1
*Objectives:*
- A review of module basics
This exercise is about some of the more tricky details of library modules.
Start this exercise by creating a very simple library module:
```python
# simplemod.py
x = 42 # A global variable
# A simple function
def foo():
print('x is', x)
# A simple class
class Spam:
def yow(self):
print('Yow!')
# A scripting statement
print('Loaded simplemod')
```
## (a) Module Loading and System Path
Try importing the module you just created:
```python
>>> import simplemod
Loaded simplemod
>>> simplemod.foo()
x is 42
>>>
```
If this failed with an `ImportError`, your path setting is
flaky. Look at the value of `sys.path` and fix it.
```python
>>> import sys
>>> sys.path
... look at the result ...
>>>
```
## (b) Repeated Module Loading
Make sure you understand that modules are only loaded
once. Try a repeated import and notice how you do not see
the output from the `print` function:
```python
>>> import simplemod
>>>
```
Try changing the value of `x` and see that a repeated import
has no effect.
```python
>>> simplemod.x
42
>>> simplemod.x = 13
>>> simplemod.x
13
>>> import simplemod
>>> simplemod.x
13
>>>
```
Use `importlib.reload()` if you want to force a module to reload.
```python
>>> import importlib
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
>>> simplemod.x
42
>>>
```
`sys.modules` is a dictionary of all loaded modules. Take
a look at it, delete your module, and try a repeated import.
```python
>>> sys.modules
... look at output ...
>>> sys.modules['simplemod']
<module 'simplemod' from 'simplemod.py'>
>>> del sys.modules['simplemod']
>>> import simplemod
Loaded simplemod
>>>
```
## (c) from module import
Restart Python and import a selected symbol from a module.
```python
>>> ############### [ RESTART ] ###############
>>> from simplemod import foo
Loaded simplemod
>>> foo()
x is 42
>>>
```
Notice how this loaded the entire module (observe the output of
the print function and how the `x` variable is used).
When you use `from`, the module object itself is not
visible. For example:
```python
>>> simplemod.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'simplemod' is not defined
>>>
```
Make sure you understand that when you export things from a module,
they are simply name references. For example, try this and explain:
```python
>>> from simplemod import x,foo
>>> x
42
>>> foo()
x is 42
>>> x = 13
>>> foo()
x is 42 # !! Please explain
>>> x
13
>>>
```
## (d) Broken reload()
Create an instance:
```python
>>> import simplemod
>>> s = simplemod.Spam()
>>> s.yow()
Yow!
>>>
```
Now, go to the `simplemod.py` file and change the implementation of `Spam.yow()` to the
following:
```python
# simplemod.py
...
class Spam:
def yow(self):
print('More Yow!')
```
Now, watch what happens on a reload. Do not restart Python for this part.
```python
>>> importlib.reload(simplemod)
Loaded simplemod
<module 'simplemod' from 'simplemod.py'>
>>> s.yow()
'Yow!'
>>> t = simplemod.Spam()
>>> t.yow()
'More Yow!'
>>>
```
Notice how you have two instances of `Spam`, but they're using different implementations
of the `yow()` method. Yes, actually both versions of code are loaded at the same time.
You'll find other oddities as well. For example:
```python
>>> s
<simplemod.Spam object at 0x1006940b8>
>>> isinstance(s, simplemod.Spam)
False
>>> isinstance(t, simplemod.Spam)
True
>>>
```
Bottom line: It's probably best not to rely on reloading for anything important.
It might be fine if you're just trying to debug some things (as long as you're
aware of its limitations and dangers).
\[ [Solution](soln9_1.md) | [Index](index.md) | [Exercise 8.6](ex8_6.md) | [Exercise 9.2](ex9_2.md) \]
----
`>>>` Advanced Python Mastery
`...` A course by [dabeaz](https://www.dabeaz.com)
`...` Copyright 2007-2023
![](https://i.creativecommons.org/l/by-sa/4.0/88x31.png). This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/)