Python

Import modules, packages in Python 3

module chính là một file .py chứa các functions và statements được dùng để sử dụng trong các chương trình khác. Nhờ vào module mà một chương trình lớn có thể được chia thành nhiều phần nhỏ hơn để dễ dàng sử dụng, bảo trì và tái sử dụng.

package có thể được coi như là một thư mục chứa nhiều module. Để tạo package, directory cần chứa file __init__.py. File __init__.py có thể để trống hoặc chứa các khởi tạo cho package. File này sẽ được thực thi đầu tiên khi package được import.


ABSOLUTE IMPORTS

import Statement

import [package.]* module [as name] [, [package.]* module [as name]]*

import statement cho phép truy cập vào các module. Các attribute của module sẽ được truy cập từ chương trình chính với cú pháp: module.attribute

Dưới đây là ví dụ về module và package:

|—- mainprogram.py
|—- mymodule.py
|—- mypackage/
—-|—- __init__.py
—-|—- moduleA.py
—-|—- moduleB.py
—-|—- subpackage1/
——–|—- __init__.py
——–|—- moduleX.py
——–|—- moduleY.py
—-|—- subpackage2/
——–|—- __init__.py
——–|—- moduleZ.py

Chúng ta sẽ bắt đầu với các trường hợp đơn giản nhất, khi các file __init__.py được để trống.

Example 1: Module imports
mymodule.py

def sayHi():
    print("Hi, I'm mymodule.py")

mainprogram.py

import mymodule

def sayHi():
    mymodule.sayHi()
    print("I'm imported into mainprogram.py")

sayHi()

Output:
$ python3 mainprogram.py
Hi, I’m mymodule.py
I’m imported into mainprogram.py

moduleB.py

def sayHi():
    print("Hi, I'm moduleB.py")

moduleA.py

import moduleB

def sayHi():
    moduleB.sayHi()
    print("I'm imported into moduleA.py")

sayHi()

Output:
$ python3 moduleA.py
Hi, I’m moduleB.py
I’m imported into moduleA.py

Qua example 1 ta thấy rằng, khi chương trình chính và các module cùng thuộc một directory, việc import các module khá đơn giản.

Example 2 – Package imports
moduleB.py

def sayHi():
    print("Hi, I'm moduleB.py")

mainprogram.py

import mypackage.moduleB as moduleB
import mypackage.subpackage1.moduleX as moduleX
import mypackage.subpackage2.moduleZ as moduleZ

def sayHi():
    moduleB.sayHi()
    print("I'm imported into mainprogram.py")
    moduleX.sayHi()
    print("I'm imported into mainprogram.py")
    moduleZ.sayHi()
    print("I'm imported into mainprogram.py")

sayHi()

Output:
$ python3 mainprogram.py
Hi, I’m moduleB.py
I’m imported into mainprogram.py
Hi, I’m moduleX.py
I’m imported into mainprogram.py
Hi, I’m moduleZ.py
I’m imported into mainprogram.py

Trong example 2 ta đã thực hiện import các module trong package với cú pháp:

import dir1.dir2.dir3.module as name

Chúng ta thấy rằng, khi package gồm nhiều subpackage, việc import modules sẽ khá dài dòng, tuy nhiên điều này sẽ được giải quyết ở phần tiếp theo của bài viết.


from Statement

from Statement cho phép import các attribute cụ thể của module, vì nó sao chép tên của các attribute từ module vào chương trình chính, nên các attribute này sẽ được truy cập trực tiếp bằng chính tên của nó. Cú pháp import như sau:

from [package.]* module import [(] name [as othername] [, name [as othername]]* [)]

Ngoài ra, với from Statement chúng ta cũng có thể import một module cụ thể từ package, tuy nhiên nên hạn chế cách import này vì dễ gây nhầm lẫn giữa import attribute và import module (do chúng ta không phân biệt ngay được đối tượng được import là attribute hay module). Cú pháp import như sau:

from [package.]* import module 

Example 3: from module import function as alias
mainprogram.py

from mypackage.subpackage1.moduleX import sayHi as X_sayHi

def sayHi():
    X_sayHi()
    print("I'm imported into mainprogram.py")

sayHi()

moduleX.py

def sayHi():
	print("Hi, I'm moduleX")

Output:
$ python3 mainprogram.py
Hi, I’m moduleX.py
I’m imported into mainprogram.py

Ở example 3, chúng ta đã dùng from statement để import function sayHi() từ moduleX.py vào mainprogram.py với alias X_sayHi và sử dụng function này không cần tiền tố moduleX.


Executing modules as scripts

Sử dụng điều kiện if __name__ == ‘__main__’ ở cuối file để execute module như script. Như vậy module vừa có thể được import cũng như chạy như một script bình thường.

Example 4: Executing modules as scripts

moduleA.py

def sayHi():
    print("Hi, I'm moduleA.py");

if __name__ == '__main__':
    sayHi()
    print("I'm running as script")

Output:
$ python3 moduleA.py
Hi, I’m moduleA.py
I’m running as script
$ python3
>>> import moduleA
>>> moduleA.sayHi()
Hi, I’m moduleA.py

Như vậy, moduleA.py không thực hiện đoạn code trong if __name__ == ‘__main__’ khi nó được import.


RELATIVE IMPORTS

Ở các ví dụ trước, chúng ta chỉ mới tìm hiểu về import trực tiếp các modules trong cùng một package hoặc subpackage, chẳng hạn: import mymodule vào mainprogram, import moduleB vào moduleA, import moduleB vào mainprogram. Nhưng nếu import moduleB vào moduleA và sau đó import moduleA vào mainprogram thì sao?

Note that relative imports are based on the name of the current module. Since the name of the main module is always “__main__”, modules intended for use as the main module of a Python application must always use absolute imports.

Intra-package References

the from statement (but not import) may use leading dots in module names to specify intra-package module references—imports which are relative to the package directory in which the importing module resides only.

Khi package bao gồm nhiều subpackages, chúng ta có thể sử dụng absolute importrelative import để import các module giữa các subpackages.

Chú ý:

  • KHÔNG THỂ thực hiện relative import khi “Executing modules as scripts“.
  • Tránh nhầm lẫn giữa absolute import from statement và intra-package reference from statement (with leading dots).

Example 5: Nested imports
moduleB.py

def sayHi():
    print("Hi, I'm moduleB")

moduleA.py

from . import moduleB
# hoặc from mypackage import moduleB

def sayHi():
    moduleB.sayHi()
    print("I'm imported into moduleA.py")
    print("Hi, I'm moduleA.py");

moduleZ.py

from .. import moduleB
# hoặc from mypackage import moduleB

def sayHi():
    moduleB.sayHi()
    print("I'm imported into moduleZ.py")
    print("Hi, I'm moduleZ")

moduleY.py

from ..subpackage2 import moduleZ
# hoặc from mypackage.subpackage2 import moduleZ

def sayHi():
    moduleZ.sayHi()
    print("I'm imported into moduleY.py")
    print("Hi, I'm moduleY")

mainprogram.py

import mypackage.moduleA as moduleA
import mypackage.subpackage1.moduleY as moduleY
import mypackage.subpackage2.moduleZ as moduleZ

def sayHi():
    moduleA.sayHi()
    print("I'm imported into mainprogram.py")
    moduleY.sayHi()
    print("I'm imported into mainprogram.py")
    moduleZ.sayHi()
    print("I'm imported into mainprogram.py")

sayHi()

Output:
$ python3 mainprogram.py
Hi, I’m moduleB
I’m imported into moduleA.py
Hi, I’m moduleA
I’m imported into mainprogram.py
Hi, I’m moduleB
I’m imported into moduleZ.py
Hi, I’m moduleZ
I’m imported into moduleY.py
Hi, I’m moduleY
I’m imported into mainprogram.py
Hi, I’m moduleB
I’m imported into moduleZ.py
Hi, I’m moduleZ
I’m imported into mainprogram.py


Editing __init__.py file

Ở các ví dụ đã qua ta thấy rằng, khi package gồm nhiều subpackages, việc import là khá dài dòng. Để làm đơn giản việc import, ta cần thực hiện một vài khởi tạo ở file __init__.py ở từng subpackage.

Example 6:

Sử dụng lại các file như ở example 5, chúng ta chỉnh sửa file mypackage\__init__.py và mainprogram.py:

mypackage/ __init__.py

from .subpackage1 import moduleX, moduleY
from .subpackage2 import moduleZ

mainprogram.py

from mypackage import moduleA, moduleY, moduleZ

def sayHi():
    moduleA.sayHi()
    print("I'm imported into mainprogram.py")
    moduleY.sayHi()
    print("I'm imported into mainprogram.py")
    moduleZ.sayHi()
    print("I'm imported into mainprogram.py")

sayHi()

Output:
$ python3 mainprogram.py
Hi, I’m moduleB
I’m imported into moduleA.py
Hi, I’m moduleA
I’m imported into mainprogram.py
Hi, I’m moduleB
I’m imported into moduleZ.py
Hi, I’m moduleZ
I’m imported into moduleY.py
Hi, I’m moduleY
I’m imported into mainprogram.py
Hi, I’m moduleB
I’m imported into moduleZ.py
Hi, I’m moduleZ
I’m imported into mainprogram.py

Kết quả nhận được không thay đổi so với example 5, nhưng phần import của mainprogram.py đã ngắn gọn hơn vì ta đã thêm vào file mypackage/ __init__.py một số khởi tạo:

from .subpackage1 import moduleX, moduleY

from .subpackage2 import moduleZ

File mypackage/ __init__.py có thể để trống hoặc chứa một số khởi tạo sẽ được ngầm thực thi đầu tiên khi mypackage được import (bởi cả hai statements from và import). Theo ví dụ trên thì chúng ta đã thực hiện relative import các moduleX, moduleY và moduleZ từ mypackage/ __init__.py, do đó khi import các module này vào mainprogram, chúng ta có thể trực tiếp sử dụng from mypackage import moduleY.


SUMMARY

Qua bài viết này chúng ta đã tìm hiểu về cách import modules, packages trong Python 3. Để code trở nên dễ hiểu, chúng ta chỉ sử dụng from statement trong relative import và khi cần import một attribute cụ thể của module. Tránh sử dụng from statement để import trực tiếp các module. Cảm ơn các bạn đã theo dõi bài viết.

Thân ái và quyết thắng.

Reference:
[1] Python 101: All about imports.
[2] The import system.
[3] Modules – Python 3.6.4

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s