13 | Building blocks: Python modularization

table of Contents

 

1. Simple modularization

2. Project modularization

Three, the magical if__name__=='__main__'

Four, summary

Five, thinking questions


1. Simple modularization

You can split functions, classes, and constants into different files, put them in the same folder, and then use the method of from your_file import function_name, class_name to call, and then these functions can be used directly in the file.

# utils.py

def get_sum(a, b):
    return a + b
# class_utils.py

class Encoder(object):
    def encode(self, s):
        return s[::-1]

class Decoder(object):
    def decode(self, s):
        return ''.join(reversed(list(s)))
# class_utils.py

class Encoder(object):
    def encode(self, s):
        return s[::-1]

class Decoder(object):
    def decode(self, s):
        return ''.join(reversed(list(s)))

In the above code, the get_sum() function is defined in utils.py, while the Encoder and Decoder classes can be directly called from import in the main function in class_utils.py to import what we need.

The file structure is as follows:

.
├── utils
│   ├── utils.py
│   └── class_utils.py
├── src
│   └── sub_main.py
└── main.py

It is easy to see that when main.py calls the module of the directory, you only need to use. Instead of / to represent the subdirectory, and utils.utils represents the utils.py module of the utils subfile.

Except for some special circumstances, import must be at the forefront.

We also need to create a new __init__.py in the folder where the module is located. The content can be empty or used to express the module interface exposed by the package. However, in fact, this is the python2 specification. In python3, __init__.py is not necessary.

2. Project modularization

In Linux, start with / to indicate the path from the root directory to the leaf node, eg:/home/ubuntn/Desktop/my_project/test.py This method is called an absolute path.

In addition, for any two files, we have a path from one file to another. eg:/home/ubuntu/Downloads/example.json. If you access from test.py, you need to write it as ../../Downloads/example.json, which means the upper level directory, this method means a relative path.

Usually a python file will have a location when it is running, the first is the folder where the file is located, of course, this path can be changed. Run sys.path.append("..") to change the location of the current python interpreter. The relative path is not a good choice, because if the code migrates, the relative position will cause refactoring and errors. For an independent project, it is best to start from the root directory of the project, which is called an absolute path.

Advantages of absolute path:

(1) Simplify dependency management

(2) The version is unified, there is no use of a new module, but a series of function crashes, and all upgrades need to pass unit tests to continue.

(3) Code traceability can be easily traced, where an API is called from, and how its historical version is iteratively developed and changed.

When working on a project, it is impossible to put all the world’s code in one file, but the idea of ​​modularity is still necessary, that is, the project is the most basic directory, and all module calls must go through the root directory. Import by indexing down layers.

You can use pycharm to create a project, the project structure is:

.
├── proto
│   ├── mat.py
├── utils
│   └── mat_mul.py
└── src
    └── main.py

 

# utils/mat_mul.py

from proto.mat import Matrix

def mat_mul(matrix_1: Matrix, matrix_2: Matrix):
    assert matrix_1.m == matrix_2.n
    n, m, s = matrix_1.n, matrix_1.m, matrix_2.m
    result = [[0 for _ in range(n)] for _ in range(s)]
    for i in range(n):
        for j in range(s):
            for k in range(m):
                result[i][k] += matrix_1.data[i][j] * matrix_2.data[j][k]

    return Matrix(result)
# src/main.py

from proto.mat import Matrix
from utils.mat_mul import mat_mul


a = Matrix([[1, 2], [3, 4]])
b = Matrix([[5, 6], [7, 8]])

print(mat_mul(a, b).data)

########## 输出 ##########

[[19, 22], [43, 50]]

This example is similar to the above, but pay attention to utils/mat_mul.py, you will find that the way it imports Matrix is ​​from proto.mat, which is directly imported from the project directory, and then the module mat.py is imported in sequence. Matrix instead of using...import the upper level folder.

Next and the project are built using pycharm. Put different modules in different files, and cross-module calls are directly indexed from the top level, which is very convenient in one step.

In fact, when the python interpreter encounters an import, it will look for modules in a specific list. This specific list can be obtained in the following way:

import sys  

print(sys.path)

########## 输出 ##########

['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']

The first item is empty because the first item is set to the absolute address of the root directory. In this way, every time you run main.py and the import function is executed, it will go to the project root directory to find the corresponding package.

There are two ways to make the general python environment can do it

import sys

sys.path[0] = '/home/ubuntu/workspace/your_projects'

Three, the magical if__name__=='__main__'

Python can also write code directly, if __name__ =='__main__'.

The project structure is as follows:

.
├── utils.py
├── utils_with_main.py
├── main.py
└── main_2.py
# utils.py

def get_sum(a, b):
    return a + b

print('testing')
print('{} + {} = {}'.format(1, 2, get_sum(1, 2)))
# utils_with_main.py

def get_sum(a, b):
    return a + b

if __name__ == '__main__':
    print('testing')
    print('{} + {} = {}'.format(1, 2, get_sum(1, 2)))
# main.py

from utils import get_sum

print('get_sum: ', get_sum(1, 2))

########## 输出 ##########

testing
1 + 2 = 3
get_sum: 3
# main_2.py

from utils_with_main import get_sum

print('get_sum: ', get_sum(1, 2))

########## 输出 ##########

get_sum_2: 3

import will automatically execute all exposed code when importing a file. If you want to encapsulate a thing into a module and want it to be executable, you must put the execution code in if __name__=='__main__' the following.

In fact, __name__ is a magic built-in parameter of python, which is essentially a precious attribute of the module object. When the import statement is used, __name__ will be assigned the name of the module, which is naturally not equal to __main__.

Four, summary

1. Through absolute path and relative path, we can import modules.

2. Modularization is very important in large-scale projects, the index of the module is done through the absolute path, and the absolute path starts from the root directory of the program

3. Remember to use if __name__ =='__main__' to avoid execution during import.

Five, thinking questions

What is the difference between from module_name import * and import module_name?

from module_name import * is to import all the content in module_name, you can directly call the internal method; import module_name is to import module_name in the form of module_name.function in the code.

Guess you like

Origin blog.csdn.net/yanyiting666/article/details/92799312