What should we know about the Python Packages?
Tags: python, beginners, package
Published: 2020-08-08 12:30:33


!!! note Package --- just a special type of module, it can contain other modules, even packages
!!!

```python
>>> import urllib
>>> import urllib.request
>>> type(urllib)
<class 'module'>
>>> type(urllib.request)
<class 'module'>
```

- urllib.request is nested in urllib
- in this case: urllib is a package and urllib.request is a module

```python
>>> urllib.__path__
['/usr/lib/python3.7/urllib']
>>> urllib.request.__path__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'urllib.request' has no attribute '__path__'
>>> 
```

`__path__` is attribu list of file system path indicating where urllib lives and searches to find nested modules

This is a nature of distinction of packages and modules:
- packages are generally represented by directories.
- modules represented by single files.

### How python locates packages?
When we are asking python to load a package, it looks to your file sys. and loads corresponding code.
How python knows where to look?
The answer is python checks path attribute of the standard sys librariy
```python
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/kamil/.local/lib/python3.7/site-packages', '/usr/local/lib/python3.7/dist-packages', '/usr/lib/python3/dist-packages']
```
When we are asking python to import package it starts checking through the directories in `sys.path`.

### sys.path
```python
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/kamil/.local/lib/python3.7/site-packages', '/usr/local/lib/python3.7/dist-packages', '/usr/lib/python3/dist-packages']
```
It can be even bigger, it depends on how and how many third party packages we are installed.

```python
>>> sys.path[0]
'' #It is empty when we run python without argument $python3
>>>
``` 
!!! note sys.path[0]  --- instructs python to first look in the current directory
!!!

### PYTHONPATH
Environment variable listing path added to the sys.path

Format of PYTHONPATH is the PATH variable of your system:
- Windows: it is a semicolon seperated list of directories
- Linux and MacOS: it is a colon(:) seperated list of directories

```
$ export PYTHONPATH=not_searched 
$ python3
>>> import sys
>>> [ p in sys.path if not_searched in p]
[path to not_searched]
```
---
# Basic Package Usage
How are the packages implemented?

To create a normal package, you simply creating normal python source file and make sure that it is on sys.path.

sys.path/mypackage(your package dir)/`__init__`.py

!!! note `__init__` file is often called package init file, is what makes the package a module.
!!!

Let's go the our project directory:
- `mkdir reader` --- make a directory
- `touch reader/__init__.py` --- initialize module
- `python3` --- open REPL
- `import reader` 
As we expected it will import it as module
```python
>>> import reader
>>> type(reader)
<class 'module'>
>>> reader.__file__
'/home/kamil/my_projects/project/reader/__init__.py'
```

Lets create our module named reader.py in our reader package
- `touch reader.py`
- add the code below to reader.py:
  ```python
  class Reader:
    
    def __init__(self, filename):
      self.filename = filename
      self.f = open(filename, "rt")
    
    def read(self):
      return self.f.read()
    
    def close(self):
      return self.f.close()
  ``` 
 - run REPL:
  ```python
>>> from reader.reader import Reader
>>> Reader("reader/reader.py")
<reader.reader.Reader object at 0x7fe18e924ed0>
>>> ra = Reader("reader/reader.py")
>>> ra.read
<bound method Reader.read of <reader.reader.Reader object at 0x7fe18e92b1d0>>
>>> ra.read()
"class Reader:\n    def __init__(self,filename):\n        self.filename = filename\n        self.f = open(self.filename, 'rt')\n    \n    def close(self):\n        return self.f.close()\n\n    def read(self):\n        return self.f.read()"
>>> ra.close()
  ```
  - in order to get rid of second reader in our import
  in init file:
    ```python
      from reader import Reader
    ```
- That's all.

- Packages are Modules that contains other modules.
- Packages are generally implemented as directories containing a special `__init__.py` file
- The `__init__.py` file is executed when the package is imported
- Packages contain sub packages which themselves are implemented wit `__init__.py` files in directories.