Làm Chủ Python Virtual Environment - Môi Trường Lập Trình Ảo ?

Làm Chủ Python Virtual Environment - Môi Trường Lập Trình Ảo ?

Là một lập trình viên chuyên nghiệp Python, việc sử dụng thành thạo môi trường lập trình "ảo" gần như là bắt buộc. Môi trường "ảo" trong Python được thiết lập như thế nào? Có những cách thiết lập ra làm sao ? Tại sao phải sử dụng virtual environments? Bài viết dưới đây sẽ đưa ra các luận điểm và đề mục cũng như cách giải thích đơn giản giúp các bạn có thể nhanh chóng tiếp cận với virtual environments.

Ghi chú: Tôi xin phép viết tắt VE thay cho từ Virtual environment và tạm dừng dịch nghĩa từ khóa trên sang tiếng Việt là môi trường "ảo" để có thể giữ nguyên ý nghĩa của từ khóa.
Bài viết này được tôi thực hiện trên Windows vì các bài hướng dẫn về VE trên Linux đã hơi bị nhiều rồi. Và các user sử dụng Linux thì thuộc vào thành phần expert-user rồi nên chắc...không cần hướng dẫn nhiều họ cũng có thể làm được.

1. Giới thiệu Virtual environment (VE) trong Python

Là một lập trình viên Python, bạn không thể chỉ làm mãi một dự án với một số library/module/framework được cài đặt thẳng vào thư viện gốc được. Bạn phải luôn sẵn sàng với việc đầu tuần code Flask-API trên nền tảng Python 3.6.x; giữa tuần thì sửa một web-application của Django trên nền tảng Python 3.7.x; cuối tuần bạn lại thấy Python 3.9.0 vừa mới release, bạn muốn test một số feature mới được công bố; à, còn chưa kể dự án Odoo10 đang nhận maintain và chạy trên nền tảng Python2.7 nữa chứ.
Mỗi dự án lại có một loạt cái thư viện khác nhau, Dự án Flask A dùng thư viện Flask 0.12, dự án Flask B lại dùng thư viện Flask 1.02; hoặc như Django hiện tại có nhiều dự án chạy song song 2.2, 3.0, ....
Bạn chỉ có một cái laptop mà với mỗi project như trên bạn không thể nào cài đặt chung hết trên thư mục cài đặt gốc của Python được. Chẳng nhẽ mỗi dự án lại cài một bản Python sang một thư mục khác nhau và thực hiện khởi tạo môi trường thông dịch một cách thủ công ?

Sớm nắm bắt được nhu cầu của các lập trình viên, "ông chú Python" - Mr Guido và các cộng sự đã cho ra đời một công cụ "chất" để hỗ trợ các lập trình viên được khám phá thoải mái với Python là Virtual environment.

Virtual Environment dịch nôm na là môi trường ảo. Cũng giống như máy ảo (Virtual Machine), Virtual Environment thiết lập một môi trường ảo, cho phép bạn thoải mái thực hiện "vọc" (cài đặt rồi xóa, cài đặt các phiên bản khác nhau) lung tung với các packages của Python mà không sợ làm ảnh hưởng đến những dự án đang có sẵn.

Lợi ích của việc sử dụng VE.

Trên máy tính của tôi đang cài song song 3 phiên bản của Python là Python 2.7, 3.6, 3.8, 3.9. Do đặc thù của mỗi dự án lại sử dụng các package khác nhau nên mỗi dự án tôi sẽ tạo cho nó một VE. Tại mỗi VE, tôi thoải mái cài đặt các thư viện cần dùng mà không phải lo nghĩ đến việc cài thư viện này sẽ làm ảnh hưởng đến việc khởi chạy các dự án khác vì mỗi VE là một môi trường ảo hoàn toàn độc lập.

Ví dụ minh họa: 

Ngoài lợi ích trên, VE còn cung cấp chức năng cho phép export chính xác các package đang sử dụng trong VE (chính xác đến tận version bao nhiêu), file cấu hình môi trường này thường được đặt tên là requirements.txt).
Với mỗi dự án, khi đẩy lên git hoặc các SVN khác, tôi sẽ cần gắn thêm file cấu hình môi trường ảo 'requirements.txt' này vào.
Khi cần xây dựng VE cho dự án ở một môi trường làm việc khác, tôi sẽ thực hiện import file requirements.txt vào VE là được. Việc import vào cũng đơn giản như export vậy, hệ thống sẽ tự động thực hiện sắp xếp các thư viện theo thứ tự để thực hiện install vào VE.
Thật là tiện lợi đúng không?

2. Cách xây dựng và sử dụng VE.

Theo thời gian và nhu cầu công việc, Python cung cấp nhiều cách thức để thực hiện tạo ra các VE, dưới đây, tôi sẽ giới thiệu với các bạn một số cách mà thường được các lập trình viên dùng nhiều.

2.1. Sử dụng công cụ virtualenv

Virtualenv gần như là một công cụ thường gặp nhất với các lập trình viên Python khi muốn thiết lập một VE (https://virtualenv.pypa.io/en/latest/)
Trước khi muốn sử dụng nó thì chúng ta sẽ phải thực hiện install ra. Với terminal mặc định trên máy của bạn, bạn chỉ cần gõ dòng lệnh:  pip install virtualenv

Kết quả sẽ như dưới đây:

 PS C:\Users\quangvinh1986> pip install virtualenv
Collecting virtualenv
  Downloading https://files.pythonhosted.org/packages/be/98/8c548c1b11391695c9de2660a289bedfb7c2784651e9f93449159ca8bf81/virtualenv-20.0.33-py2.py3-none-any.whl (4.9MB)
     |████████████████████████████████| 4.9MB 3.3MB/s
Collecting distlib<1,>=0.3.1 (from virtualenv)
  Downloading https://files.pythonhosted.org/packages/f5/0a/490fa011d699bb5a5f3a0cf57de82237f52a6db9d40f33c53b2736c9a1f9/distlib-0.3.1-py2.py3-none-any.whl (335kB)
     |████████████████████████████████| 337kB 1.1MB/s
Collecting filelock<4,>=3.0.0 (from virtualenv)
  Downloading https://files.pythonhosted.org/packages/93/83/71a2ee6158bb9f39a90c0dea1637f81d5eef866e188e1971a1b1ab01a35a/filelock-3.0.12-py3-none-any.whl
Requirement already satisfied: six<2,>=1.9.0 in c:\program files\python38\lib\site-packages (from virtualenv) (1.15.0)
Collecting appdirs<2,>=1.4.3 (from virtualenv)
  Downloading https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl
Installing collected packages: distlib, filelock, appdirs, virtualenv
Successfully installed appdirs-1.4.4 distlib-0.3.1 filelock-3.0.12 virtualenv-20.0.33

Sau khi cài đặt, thực hiện kiểm tra version của virtualenv

virtualenv 20.0.33 from c:\program files\python38\lib\site-packages\virtualenv\__init__.py

Sau khi install thư viện, thực hiện di chuyển đến vị trí muốn đặt VE. Tại vị trí này, chúng ta thực hiện cài đặt VE, bằng câu lệnh: virtualenv hr_api_django2_env . Trong đó hr_api_django2_env là tên của VE mà chúng ta muốn đặt. Thông thường tôi có thói quen đặt tên theo project và framework chủ đạo hoặc package chủ đạo, với tiếp hậu ngữ là _env (đây là cách đặt tên để dễ nhớ với tôi, với các bạn thì tùy theo style của mỗi người). 

PS C:\Users\quangvinh1986> E:
PS E:\> cd E:\code_learn\VESamples
PS E:\code_learn\VESamples> virtualenv hr_api_django2_env
created virtual environment CPython3.8.2.final.0-64 in 6161ms
  creator CPython3Windows(dest=E:\code_learn\VESamples\hr_api_django2_env, clear=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\quangvinh1986\AppData\Local\pypa\virtualenv)
    added seed packages: pip==20.2.3, setuptools==50.3.0, wheel==0.35.1
  activators BashActivator,BatchActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator
PS E:\code_learn\VESamples> ls


    Directory: E:\code_learn\VESamples


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         10/9/2020   9:52 PM                hr_api_django2_env

Như vậy là chúng ta đã khởi tạo được VE cho dự án hr_api dự kiến sẽ sử dụng django2.

Chúng ta cùng xem bên trong thư mục VE có chứa những gì nhé.

PS E:\code_learn\VESamples> ls -l .\hr_api_django2_env\


    Directory: E:\code_learn\VESamples\hr_api_django2_env


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         10/9/2020   9:52 PM                Lib
d-----         10/9/2020   9:52 PM                Scripts
-a----         10/9/2020   9:52 PM             42 .gitignore
-a----         10/9/2020   9:52 PM            293 pyvenv.cfg

Bên trong thư mục VE có chứa 2 thư mục con Lib và Scripts, kèm 1 file config cho môi trường.

PS E:\code_learn\VESamples\hr_api_django2_env> ls -l .\Lib\


    Directory: E:\code_learn\VESamples\hr_api_django2_env\Lib


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         10/9/2020   9:52 PM                site-packages

Thư mục Lib có chứa thư mục site-packages, như vậy đây sẽ là nơi chứa các package mà chúng ta sẽ cài đặt vào VE.

PS E:\code_learn\VESamples\hr_api_django2_env> ls -l .\Lib\site-packages\


    Directory: E:\code_learn\VESamples\hr_api_django2_env\Lib\site-packages


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         10/9/2020   9:52 PM                pip
d-----         10/9/2020   9:52 PM                pip-20.2.3.dist-info
d-----         10/9/2020   9:52 PM                pkg_resources
d-----         10/9/2020   9:52 PM                setuptools
d-----         10/9/2020   9:52 PM                setuptools-50.3.0.dist-info
d-----         10/9/2020   9:52 PM                wheel
d-----         10/9/2020   9:52 PM                wheel-0.35.1.dist-info
d-----         10/9/2020   9:52 PM                _distutils_hack
-a----         10/9/2020   9:52 PM            152 distutils-precedence.pth
-a----         10/9/2020   9:52 PM            126 easy_install.py
-a----         10/9/2020   9:52 PM              0 pip-20.2.3.virtualenv
-a----         10/9/2020   9:52 PM              0 setuptools-50.3.0.virtualenv
-a----         10/9/2020   9:52 PM              0 wheel-0.35.1.virtualenv
-a----         10/9/2020   9:52 PM             18 _virtualenv.pth
-a----         10/9/2020   9:52 PM           5792 _virtualenv.py

Hiện tại thì thư mục này trên VE đồng bộ với thư mục site-packages của Python3.8 trên máy của tôi (do tôi thường cài đặt package vào từng VE riêng biệt), nếu lỡ máy của bạn đã cài một số package sẵn rồi, bạn không muốn các VE sẽ kéo các package đó vào thì khi thực hiện khởi tạo VE, bạn thêm tham số --no-site-packages vào là được.

Ví dụ:
virtualenv --no-site-packages hr-api-django3-env

Tiếp tục khám phá xem thư mục Scripts có gì nhé.

PS E:\code_learn\VESamples\hr_api_django2_env> ls -l .\Scripts\


    Directory: E:\code_learn\VESamples\hr_api_django2_env\Scripts


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         10/9/2020   9:52 PM           2235 activate
-a----         10/9/2020   9:52 PM           1035 activate.bat
-a----         10/9/2020   9:52 PM           3085 activate.fish
-a----         10/9/2020   9:52 PM           1755 activate.ps1
-a----         10/9/2020   9:52 PM           1176 activate.xsh
-a----         10/9/2020   9:52 PM           1193 activate_this.py
-a----         10/9/2020   9:52 PM            510 deactivate.bat
-a----         10/9/2020   9:52 PM         106381 easy_install-3.8.exe
-a----         10/9/2020   9:52 PM         106381 easy_install.exe
-a----         10/9/2020   9:52 PM         106381 easy_install3.8.exe
-a----         10/9/2020   9:52 PM         106381 easy_install3.exe
-a---l         10/9/2020   9:52 PM              0 libcrypto-1_1.dll
-a---l         10/9/2020   9:52 PM              0 libffi-7.dll
-a---l         10/9/2020   9:52 PM              0 libssl-1_1.dll
-a----         10/9/2020   9:52 PM         106372 pip-3.8.exe
-a----         10/9/2020   9:52 PM         106372 pip.exe
-a----         10/9/2020   9:52 PM         106372 pip3.8.exe
-a----         10/9/2020   9:52 PM         106372 pip3.exe
-a----         10/9/2020   9:52 PM             24 pydoc.bat
-a---l         10/9/2020   9:52 PM              0 pyexpat.pyd
-a---l         10/9/2020   9:52 PM              0 python.exe
-a---l         10/9/2020   9:52 PM              0 python3.dll
......


Thì ra thư mục này chứa các file khởi chạy của Python như pip.exe, pip3.exe, python.exe,....
Trong thư mục Scripts có 2 file quan trọng là activate.bat và deactivate.bat để thực hiện khởi chạy và tắt VE của bạn.

Khởi chạy VE:
Để khởi chạy VE, từ CMD, chúng ta gọi đến file activate.bat

E:\code_learn\VESamples\hr_api_django2_env>Scripts\activate.bat

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>

Sau khi thực hiện active thành công thì phía trên đầu của đường dẫn sẽ có tên của VE ở trong dấu (hr_api_django2_env)


Thực hiện install một package vào VE:
Ví dụ tôi thực hiện install Django 2.2 vào VE này thì câu lệnh sẽ là:

pip install django==2.2.0

Phần này các bạn cần lưu ý: Nếu không có tham số =2.2.0 phía sau thì hệ thống sẽ tự động tìm thư viện release mới nhất trên pypi (The Python Package Index), tại thời điểm này thì Django mới nhất là phiên bản 3.1.2 (tháng 10/2020).

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip install django==2.2.0
Collecting django==2.2.0
  Downloading Django-2.2-py3-none-any.whl (7.4 MB)
     |████████████████████████████████| 7.4 MB 1.1 MB/s
Collecting sqlparse
  Downloading sqlparse-0.4.1-py3-none-any.whl (42 kB)
     |████████████████████████████████| 42 kB 1.7 MB/s
Collecting pytz
  Downloading pytz-2020.1-py2.py3-none-any.whl (510 kB)
     |████████████████████████████████| 510 kB 3.3 MB/s
Installing collected packages: sqlparse, pytz, django
Successfully installed django-2.2 pytz-2020.1 sqlparse-0.4.1

Sau khi cài đặt xong, chúng ta kiểm tra xem VE của chúng ta đã được cài đặt thành công gói django2.2.0 chưa bằng câu lệnh pip -- freeze (hoặc pip freeze):

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip -- freeze
Django==2.2
pytz==2020.1
sqlparse==0.4.1

Với kết quả hiển thị như trên thì VE của chúng ta đã có phiên bản Django2.2

Export thư viện

Để thực hiện export các package trong VE ra và để mang đến import trong các VE khác, chúng ta sẽ sử dụng syntax: pip -- freeze > requirements.txt

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip -- freeze > requirements.txt

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>dir
 Volume in drive E is New Volume
 Volume Serial Number is 642C-F508

 Directory of E:\code_learn\VESamples\hr_api_django2_env

10/09/2020  10:29 PM    <DIR>          .
10/09/2020  10:29 PM    <DIR>          ..
10/09/2020  09:52 PM                42 .gitignore
10/09/2020  09:52 PM    <DIR>          Lib
10/09/2020  09:52 PM               293 pyvenv.cfg
10/09/2020  10:30 PM                44 requirements.txt
10/09/2020  10:18 PM    <DIR>          Scripts
               3 File(s)            379 bytes
               4 Dir(s)  54,222,868,480 bytes free

File requirements.txt sẽ được tạo ra tại thư mục hiện tại mà chúng ta đang đứng. Mở file requirements.txt, chúng ta sẽ có nội dung:

Import các package vào VE

Giờ chúng ta sẽ xóa package Django2.2 sau đó thực hiện import lại vào VE bằng lệnh pip install -r requirements.txt

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip uninstall Django==2.2
Found existing installation: Django 2.2
Uninstalling Django-2.2:
  Would remove:
    e:\code_learn\vesamples\hr_api_django2_env\lib\site-packages\django-2.2.dist-info\*
    e:\code_learn\vesamples\hr_api_django2_env\lib\site-packages\django\*
    e:\code_learn\vesamples\hr_api_django2_env\scripts\django-admin.exe
    e:\code_learn\vesamples\hr_api_django2_env\scripts\django-admin.py
Proceed (y/n)? y
  Successfully uninstalled Django-2.2

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip freeze
pytz==2020.1
sqlparse==0.4.1

Như này là đã xóa thành công thư viện Django2.2 trong VE.

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip install -r requirements.txt
Collecting Django==2.2
  Using cached Django-2.2-py3-none-any.whl (7.4 MB)
Requirement already satisfied: pytz==2020.1 in e:\code_learn\vesamples\hr_api_django2_env\lib\site-packages (from -r requirements.txt (line 2)) (2020.1)
Requirement already satisfied: sqlparse==0.4.1 in e:\code_learn\vesamples\hr_api_django2_env\lib\site-packages (from -r requirements.txt (line 3)) (0.4.1)
Installing collected packages: Django
Successfully installed Django-2.2

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>pip freeze
Django==2.2
pytz==2020.1
sqlparse==0.4.1

Khi thực hiện cài đặt các package từ file requirements.txt, nếu các package đã có trong VE, thì pip sẽ bỏ qua như ví dụ trên với package pytz==2020.1, sqlparse==0.4.1.

Ngắt khởi chạy VE.

Để ngắt VE, chúng ta thực hiện đứng từ một thư mục nào đó, gọi vào file Scripts\deactivate.bat

(hr_api_django2_env) E:\code_learn\VESamples\hr_api_django2_env>Scripts\deactivate.bat
E:\code_learn\VESamples\hr_api_django2_env>

Do đã thoát khỏi VE nên dòng thông tin (hr_api_django2_env) ở đầu thư mục cũng biến mất.

Trước đây, tôi cũng thường xuyên sử dụng virtualenv do từ thời Python2.7 công cụ này gần như là mạnh nhất để xây dựng các VE. Nhược điểm của nó là phải cài đặt thêm gói package virtualenv, nếu máy tính của bạn có chứa nhiều phiên bản Python và bạn liên tục phải switch qua lại giữa các project thuộc các phiên bản khác nhau thì dùng virtualenv không phải là phương án tối ưu. Lý do:
- Khi muốn cài đặt thư viện virtualenv, bạn sẽ phải di chuyển thư mục trên terminal đến đúng vị trí chứa pip của phiên bản Python bạn cần dùng để gọi lệnh pip install virtualenv.
- Khi muốn tạo mới một VE mà không phải trên version Python mặc định, bạn cũng phải di chuyển đến vị trí chứa python.exe (với windows) và thực hiện gọi lệnh tạo VE.

C:\Users\quangvinh1986>cd C:\Program Files\Python36

C:\Program Files\Python36>dir
 Volume in drive C has no label.
 Volume Serial Number is 2A30-4687

 Directory of C:\Program Files\Python36

10/06/2020  09:36 PM    <DIR>          .
10/06/2020  09:36 PM    <DIR>          ..
10/06/2020  09:36 PM    <DIR>          DLLs
10/06/2020  09:36 PM    <DIR>          Doc
10/06/2020  09:36 PM    <DIR>          include
10/06/2020  09:36 PM    <DIR>          Lib
10/06/2020  09:36 PM    <DIR>          libs
12/24/2018  12:22 AM            30,342 LICENSE.txt
12/24/2018  12:22 AM           435,627 NEWS.txt
12/24/2018  12:19 AM            99,856 python.exe
12/24/2018  12:17 AM            58,384 python3.dll
12/24/2018  12:17 AM         3,619,856 python36.dll
12/24/2018  12:19 AM            98,320 pythonw.exe
10/06/2020  09:36 PM    <DIR>          Scripts
10/06/2020  09:36 PM    <DIR>          tcl
10/06/2020  09:36 PM    <DIR>          Tools
02/19/2018  09:06 PM            87,864 vcruntime140.dll
               7 File(s)      4,430,249 bytes
              10 Dir(s)  154,379,280,384 bytes free

C:\Program Files\Python36>cd Scripts

C:\Program Files\Python36\Scripts>dir
 Volume in drive C has no label.
 Volume Serial Number is 2A30-4687

 Directory of C:\Program Files\Python36\Scripts

10/06/2020  09:36 PM    <DIR>          .
10/06/2020  09:36 PM    <DIR>          ..
10/06/2020  09:36 PM           102,777 easy_install-3.6.exe
10/06/2020  09:36 PM           102,777 easy_install.exe
10/06/2020  09:36 PM           102,759 pip.exe
10/06/2020  09:36 PM           102,759 pip3.6.exe
10/06/2020  09:36 PM           102,759 pip3.exe
               5 File(s)        513,831 bytes
               2 Dir(s)  154,381,742,080 bytes free

C:\Program Files\Python36\Scripts>pip3.6.exe freeze

C:\Program Files\Python36\Scripts>pip3.6.exe install virtualenv
Collecting virtualenv
  Using cached https://files.pythonhosted.org/packages/be/98/8c548c1b11391695c9de2660a289bedfb7c2784651e9f93449159ca8bf81/virtualenv-20.0.33-py2.py3-none-any.whl
Collecting appdirs<2,>=1.4.3 (from virtualenv)
  Using cached https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl
Collecting distlib<1,>=0.3.1 (from virtualenv)
  Using cached https://files.pythonhosted.org/packages/f5/0a/490fa011d699bb5a5f3a0cf57de82237f52a6db9d40f33c53b2736c9a1f9/distlib-0.3.1-py2.py3-none-any.whl
Collecting filelock<4,>=3.0.0 (from virtualenv)
  Using cached https://files.pythonhosted.org/packages/93/83/71a2ee6158bb9f39a90c0dea1637f81d5eef866e188e1971a1b1ab01a35a/filelock-3.0.12-py3-none-any.whl
Collecting importlib-resources>=1.0; python_version < "3.7" (from virtualenv)
  Downloading https://files.pythonhosted.org/packages/ba/03/0f9595c0c2ef12590877f3c47e5f579759ce5caf817f8256d5dcbd8a1177/importlib_resources-3.0.0-py2.py3-none-any.whl
Collecting importlib-metadata<3,>=0.12; python_version < "3.8" (from virtualenv)
  Downloading https://files.pythonhosted.org/packages/6d/6d/f4bb28424bc677bce1210bc19f69a43efe823e294325606ead595211f93e/importlib_metadata-2.0.0-py2.py3-none-any.whl
Collecting six<2,>=1.9.0 (from virtualenv)
  Using cached https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Collecting zipp>=0.4; python_version < "3.8" (from importlib-resources>=1.0; python_version < "3.7"->virtualenv)
  Downloading https://files.pythonhosted.org/packages/15/1b/dbf5af0148ba527fb2164d2a2ecf623e77ca93877a83379a5b1aab563e40/zipp-3.3.0-py3-none-any.whl
Installing collected packages: appdirs, distlib, filelock, zipp, importlib-resources, importlib-metadata, six, virtualenv
Successfully installed appdirs-1.4.4 distlib-0.3.1 filelock-3.0.12 importlib-metadata-2.0.0 importlib-resources-3.0.0 six-1.15.0 virtualenv-20.0.33 zipp-3.3.0

C:\Program Files\Python36\Scripts>pip3.6.exe freeze
appdirs==1.4.4
distlib==0.3.1
filelock==3.0.12
importlib-metadata==2.0.0
importlib-resources==3.0.0
six==1.15.0
virtualenv==20.0.33
zipp==3.3.0

Để tạo một VE, đứng từ thư mục chứa python.exe, gọi đến thư viện virtualenv với tham số -m và thông tin đường dẫn tuyệt đối và tên của VE muốn tạo

C:\Program Files\Python36>python.exe -m virtualenv E:\code_learn\VESamples\hr_report_flask012_env
created virtual environment CPython3.6.8.final.0-64 in 4853ms
  creator CPython3Windows(dest=E:\code_learn\VESamples\hr_report_flask012_env, clear=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=C:\Users\quangvinh1986\AppData\Local\pypa\virtualenv)
    added seed packages: pip==20.2.3, setuptools==50.3.0, wheel==0.35.1
  activators BashActivator,BatchActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator

Phía bên thư mục chứa VE:

E:\code_learn\VESamples>dir
 Volume in drive E is New Volume
 Volume Serial Number is 642C-F508

 Directory of E:\code_learn\VESamples

10/10/2020  10:53 AM    <DIR>          .
10/10/2020  10:53 AM    <DIR>          ..
10/09/2020  10:29 PM    <DIR>          hr_api_django2_env
10/10/2020  10:53 AM    <DIR>          hr_report_flask012_env
10/09/2020  09:56 PM            58,146 tree
               1 File(s)         58,146 bytes
               4 Dir(s)  54,212,648,960 bytes free

E:\code_learn\VESamples>cd hr_report_flask012_env

E:\code_learn\VESamples\hr_report_flask012_env>dir
 Volume in drive E is New Volume
 Volume Serial Number is 642C-F508

 Directory of E:\code_learn\VESamples\hr_report_flask012_env

10/10/2020  10:53 AM    <DIR>          .
10/10/2020  10:53 AM    <DIR>          ..
10/10/2020  10:53 AM                42 .gitignore
10/10/2020  10:53 AM    <DIR>          Lib
10/10/2020  10:53 AM               293 pyvenv.cfg
10/10/2020  10:53 AM    <DIR>          Scripts
               2 File(s)            335 bytes
               4 Dir(s)  54,212,648,960 bytes free

E:\code_learn\VESamples\hr_report_flask012_env>Scripts\activate.bat

(hr_report_flask012_env) E:\code_learn\VESamples\hr_report_flask012_env>

2.2. Sử dụng công cụ venv

Nắm được nhược điểm của việc sử dụng package virtualenv, từ phiên bản Python3.5, đã có công cụ "chính chủ" tích hợp sẵn vào site-packages của Python, đó là công cụ venv (https://docs.python.org/3/library/venv.html). Các lập trình viên Python không cần phải cài đặt thêm package nào khác cũng có thể nhanh chóng tạo ra các VE.
Tuy nhiên một số máy tính do cài đặt bản Python-minimal nên bị thiếu thư viện, nếu bị thiếu thì cần cài bổ sung package: python3-venv (thường gặp trên máy cài hệ điều hành Linux)

Khởi tạo VE

Với bản Python mặc định trên máy tính, chỉ cần gọi lệnh python -m venv path_to_VE

E:\code_learn\VESamples>python -m venv blog_api_django3_env

E:\code_learn\VESamples>dir
 Volume in drive E is New Volume
 Volume Serial Number is 642C-F508

 Directory of E:\code_learn\VESamples

10/10/2020  11:01 AM    <DIR>          .
10/10/2020  11:01 AM    <DIR>          ..
10/10/2020  11:01 AM    <DIR>          blog_api_django3_env
10/09/2020  10:29 PM    <DIR>          hr_api_django2_env
10/10/2020  10:53 AM    <DIR>          hr_report_flask012_env
10/09/2020  09:56 PM            58,146 tree
               1 File(s)         58,146 bytes
               5 Dir(s)  54,197,891,072 bytes free

E:\code_learn\VESamples>cd blog_api_django3_env

E:\code_learn\VESamples\blog_api_django3_env>Scripts\activate.bat

(blog_api_django3_env) E:\code_learn\VESamples\blog_api_django3_env>python -V
Python 3.8.2

Với bản Python khác với bản mặc định, các làm tương tự như dùng thư viện virtualenv, chỉ khác là bạn sẽ không cần cài đặt package trước khi sử dụng.

C:\Program Files\Python36>python.exe -m venv  E:\code_learn\VESamples\blog_report_flask1_env

Sau câu lệnh tạo ra môi trường, không có phản hồi gì có nghĩ là đã tạo thành công nhé. Tại thư mục chứa VE: 

E:\code_learn\VESamples>dir
 Volume in drive E is New Volume
 Volume Serial Number is 642C-F508

 Directory of E:\code_learn\VESamples

10/10/2020  11:13 AM    <DIR>          .
10/10/2020  11:13 AM    <DIR>          ..
10/10/2020  11:01 AM    <DIR>          blog_api_django3_env
10/10/2020  11:13 AM    <DIR>          blog_report_flask1_env
10/09/2020  10:29 PM    <DIR>          hr_api_django2_env
10/10/2020  10:53 AM    <DIR>          hr_report_flask012_env
10/09/2020  09:56 PM            58,146 tree
               1 File(s)         58,146 bytes
               6 Dir(s)  54,140,325,888 bytes free

E:\code_learn\VESamples>cd blog_report_flask1_env

E:\code_learn\VESamples\blog_report_flask1_env>Scripts\activate.bat

(blog_report_flask1_env) E:\code_learn\VESamples\blog_report_flask1_env>python -V
Python 3.6.8

3. Một số lưu ý.

Phía trên tôi đã giới thiệu với các bạn các thông tin về VE và 2 phương pháp khởi tạo môi trường ảo. Phần tiếp theo đây, tôi sẽ giới thiệu với các bạn một số thông tin bổ sung cần lưu ý.

3.1. Lệnh khởi tạo và ngắt VE trên Linux/MacOS.

Trên Windows, các bạn sẽ gọi vào file activate.bat/deactivate.bat để khởi chạy và ngắt VE. Trên Lunix/MacOS, để do thư viện và môi trường khác nên việc cài đặt VE, khởi chạy VE dùng lệnh source bin/activate.

Ví dụ: Tôi sử dụng Ubuntu-WSL trên máy của tôi để demo nhé. 

[email protected]:~$ python3 -m venv blog_api_django2_env
[email protected]:~$ ls
blog_api_django2_env
[email protected]:~$ cd blog_api_django2_env/
[email protected]:~/blog_api_django2_env$ ls
bin  include  lib  lib64  pyvenv.cfg  share
[email protected]:~/blog_api_django2_env$ source bin/
activate          activate.fish     easy_install-3.6  pip3              python
activate.csh      easy_install      pip               pip3.6            python3
[email protected]:~/blog_api_django2_env$ source bin/activate
(blog_api_django2_env) [email protected]:~/blog_api_django2_env$ python -V
Python 3.6.9
(blog_api_django2_env) [email protected]:~/blog_api_django2_env$

Để ngắt khỏi VE:

(blog_api_django2_env) [email protected]:~/blog_api_django2_env$ deactivate
[email protected]:~/blog_api_django2_env$

Chỉ khác nhau về việc khởi chạy và ngắt VE, các action khác như export/import thì trên Windows và Linux/MacOS như nhau.

3.2. Sử dụng IDE Pycharm để khởi tạo VE.

Nếu bạn thường xuyên sử dụng Pycharm như một IDE chuyên dụng cho việc code các dự án Python, để bắt đầu mỗi dự án chúng ta đều phải khởi tạo VE trước.
Các bạn có thể tham khảo hướng dẫn khá chi tiết về việc này tại trang support của Pycharm: https://www.jetbrains.com/help/pycharm/configuring-local-python-interpreters.html

3.3. Không add/commit/push môi trường lên git.

Lưu ý cuối cùng tôi muốn trao đổi với các bạn là đừng bao giờ thực hiện đưa VE lên git/svn vì dung lượng của nó hơi bị ... nặng. Mặc dù trong thư mục VE đã có sẵn file .gitignore nhưng chúng ta vẫn cần lưu ý vấn đề này nhé.
Để đồng bộ được các package/framework giữa các môi trường làm việc DEVs/UAT/PRODUCTION, chúng ta chỉ việc export các package trong môi trường ra file requirements.txt và ở môi trường làm việc mới sẽ thực hiện import chúng lại.

Kết:

Trên đây, tôi đã giới thiệu với các bạn lợi ích và cách sử dụng virtual environments trong lập trình Python chuyên nghiệp. Để đảm bảo tính đầy đủ của bài viết nên bài viết khá dài, hy vọng các bạn nhớ thực hiện setup các VE cho mỗi project để mỗi lần chúng ta "vọc vạch" các thư viện/package mới không làm ảnh hưởng đến những gì đang hoạt động ổn đinh.
Cảm ơn các bạn đã đọc bài viết.