Kiểm tra xem Gói Python đã được cài đặt chưa


112

Cách tốt để kiểm tra xem một gói có được cài đặt trong tập lệnh Python hay không? Tôi biết nó dễ dàng từ trình thông dịch, nhưng tôi cần phải làm điều đó trong một tập lệnh.

Tôi đoán tôi có thể kiểm tra xem có một thư mục trên hệ thống được tạo trong quá trình cài đặt hay không, nhưng tôi cảm thấy có một cách tốt hơn. Tôi đang cố gắng đảm bảo rằng gói Skype4Py đã được cài đặt và nếu không, tôi sẽ cài đặt nó.

Ý tưởng của tôi để hoàn thành séc

  • kiểm tra một thư mục trong đường dẫn cài đặt điển hình
  • cố gắng nhập gói và nếu một ngoại lệ được ném ra, sau đó cài đặt gói

Viết tập lệnh Python để tự động khởi động Skype và sử dụng tcpdump để thu thập dữ liệu gói để tôi có thể phân tích cách mạng hoạt động khi bạn có cuộc gọi hội nghị.
Kevin

Câu trả lời:


107

Nếu ý của bạn là script python, chỉ cần làm như sau:

Python 3.3+ sử dụng sys.modules và find_spec :

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

if name in sys.modules:
    print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
    # If you choose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    print(f"{name!r} has been imported")
else:
    print(f"can't find the {name!r} module")

Python 3:

try:
    import mymodule
except ImportError as e:
    pass  # module doesn't exist, deal with it.

Python 2:

try:
    import mymodule
except ImportError, e:
    pass  # module doesn't exist, deal with it.

6
Cảnh báo: Hôm nay tôi vừa gặp phải tình huống trong đó ImportError được đưa vào trong chính mô-đun. Điều này không nên xảy ra thường xuyên, nhưng chỉ cần lưu ý rằng kiểm tra này không đáng tin cậy trong mọi trường hợp.
Koen Bok

7
Điều này không chỉ kiểm tra ; nó cũng nhập khẩu nó; xem thêm stackoverflow.com/questions/14050281/…
Jorge Leitao,

6
Đúng. Đó thường là những gì bạn muốn. Bạn có thể sử dụng mô-đun công cụ nhập để kiểm tra phức tạp hơn, nhưng phần lớn lý do duy nhất khiến bạn quan tâm nếu mô-đun được cài đặt là vì bạn muốn sử dụng nó.
Christopher

Điều này sẽ không thành công nếu bạn có một tệp khác có cùng tên với gói.
Sapphire_Brick

Chắc chắn, nhưng đó là một vấn đề hoàn toàn khác. Nếu bạn có hai mô-đun hoặc gói khác nhau có cùng tên trong đường dẫn tra cứu thì bạn đang gặp rắc rối.
Christopher

56

Cập nhật câu trả lời

Một cách tốt hơn để làm điều này là:

import subprocess
import sys

reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
installed_packages = [r.decode().split('==')[0] for r in reqs.split()]

Kết quả:

print(installed_packages)

[
    "Django",
    "six",
    "requests",
]

Kiểm tra xem đã requestsđược cài đặt chưa:

if 'requests' in installed_packages:
    # Do something

Tại sao lại theo cách này? Đôi khi bạn có xung đột tên ứng dụng. Nhập từ không gian tên ứng dụng không cung cấp cho bạn bức tranh đầy đủ về những gì được cài đặt trên hệ thống.

Lưu ý, giải pháp được đề xuất đó hoạt động:

  • Khi sử dụng pip để cài đặt từ PyPI hoặc từ bất kỳ nguồn thay thế nào khác (như pip install http://some.site/package-name.ziphoặc bất kỳ loại lưu trữ nào khác).
  • Khi cài đặt thủ công bằng cách sử dụng python setup.py install.
  • Khi cài đặt từ kho hệ thống, như sudo apt install python-requests.

Các trường hợp khi nó có thể không hoạt động:

  • Khi cài đặt ở chế độ phát triển, thích python setup.py develop.
  • Khi cài đặt ở chế độ phát triển, thích pip install -e /path/to/package/source/.

Câu trả lời cũ

Một cách tốt hơn để làm điều này là:

import pip
installed_packages = pip.get_installed_distributions()

Đối với pip> = 10.x sử dụng:

from pip._internal.utils.misc import get_installed_distributions

Tại sao lại theo cách này? Đôi khi bạn có xung đột tên ứng dụng. Nhập từ không gian tên ứng dụng không cung cấp cho bạn bức tranh đầy đủ về những gì được cài đặt trên hệ thống.

Kết quả là, bạn nhận được một danh sách các pkg_resources.Distributionđối tượng. Xem ví dụ sau:

print installed_packages
[
    "Django 1.6.4 (/path-to-your-env/lib/python2.7/site-packages)",
    "six 1.6.1 (/path-to-your-env/lib/python2.7/site-packages)",
    "requests 2.5.0 (/path-to-your-env/lib/python2.7/site-packages)",
]

Lập danh sách về nó:

flat_installed_packages = [package.project_name for package in installed_packages]

[
    "Django",
    "six",
    "requests",
]

Kiểm tra xem đã requestsđược cài đặt chưa:

if 'requests' in flat_installed_packages:
    # Do something

2
Như đã đề cập trong câu trả lời khác, có thể lỗi không bắt được. Vì vậy, tôi nghĩ rằng đây nên là câu trả lời được chấp nhận.
Jorrick Sleijster

1
Phương thức này không hoạt động với các gói như 'json' (trả về False khi import jsonthực sự hoạt động). Phương pháp ice.nicer đang hoạt động trong trường hợp này.
mountrix

1
Bằng cách nào đó, tôi cần sử dụng séc if "u'requests'" in installed_packages:từ Câu trả lời cập nhật để làm việc cho tôi. Đầu ra của print()sản xuất này trên python MacOS của tôi:[..., u'pytz', u'requests', ...]
Buju

1
@ArturBarseghyan Tôi đang sử dụng Python 2.7.10 (python hệ thống macOS) ... thực sự tôi phải sử dụng if "requests'"(lưu ý câu trích dẫn duy nhất ở cuối). không có ý nghĩa gì cả.
Buju

1
Điều này không trả lời câu hỏi: "gói 'x' đã được cài đặt chưa?". Có nhiều cách để cài đặt một gói mà không cần sử dụng pip. Ví dụ: bạn có thể tạo và cài đặt một gói từ nguồn. Câu trả lời này sẽ không tìm thấy chúng. Câu trả lời từ @ ice.nicer về find_spec()là đúng.
Arthur

43

Kể từ Python 3.3, bạn có thể sử dụng phương thức find_spec ()

import importlib.util

# For illustrative purposes.
package_name = 'pandas'

spec = importlib.util.find_spec(package_name)
if spec is None:
    print(package_name +" is not installed")

4
Sạch sẽ và đơn giản, câu trả lời tốt nhất ở đây. Điều này cần nhiều lượt ủng hộ hơn.
David Parks

5
Hãy cẩn thận. Nếu tên gói chứa dấu gạch ngang, find_spec () không thể tìm thấy nó trừ khi bạn sử dụng dấu chấm. Ví dụ: importlib.util.find_spec('google-cloud-logging')không tìm thấy gì trong khi importlib.util.find_spec('google.cloud.logging')được tìm thấy. Tên chính thức và tên mà pip hiển thị là dấu gạch ngang, không phải dấu chấm. Có thể gây nhầm lẫn do đó sử dụng một cách thận trọng.
dwich

27

Nếu bạn muốn kiểm tra từ thiết bị đầu cuối, bạn có thể chạy

pip3 show package_name

và nếu không có gì được trả lại, thì gói chưa được cài đặt.

Nếu có lẽ bạn muốn tự động hóa việc kiểm tra này, ví dụ như bạn có thể cài đặt nó nếu bị thiếu, bạn có thể có những điều sau trong tập lệnh bash của mình:

pip3 show package_name 1>/dev/null #pip for Python 2
if [ $? == 0 ]; then
   echo "Installed" #Replace with your actions
else
   echo "Not Installed" #Replace with your actions, 'pip3 install --upgrade package_name' ?
fi

Điều này có vẻ tuyệt vời nhưng nó luôn trả về "Chưa được cài đặt" cho tôi. Tại sao?
Elliptica

Bạn có thể chia sẻ kết quả đầu ra của “$ pip3 —version” và “$ pip3 show package_name”, nơi bạn thay thế package_name bằng gói mong muốn không?
Ognjen Vukovic

Mẹo Shell: bạn có thể sử dụng ifđể kiểm tra trực tiếp một lệnh thành công:if pip3 show package_name 1>/dev/null; then ...
MestreLion

6

Như một phần mở rộng của câu trả lời này :

Đối với Python 2. *, pip show <package_name>sẽ thực hiện tác vụ tương tự.

Ví dụ pip show numpysẽ trả về như sau hoặc giống nhau:

Name: numpy
Version: 1.11.1
Summary: NumPy: array processing for numbers, strings, records, and objects.
Home-page: http://www.numpy.org
Author: NumPy Developers
Author-email: numpy-discussion@scipy.org
License: BSD
Location: /home/***/anaconda2/lib/python2.7/site-packages
Requires: 
Required-by: smop, pandas, tables, spectrum, seaborn, patsy, odo, numpy-stl, numba, nfft, netCDF4, MDAnalysis, matplotlib, h5py, GridDataFormats, dynd, datashape, Bottleneck, blaze, astropy

Không phải từ một tập lệnh nhưng tuyệt vời để kiểm tra dòng lệnh. Cảm ơn
Jj Rivero

3

Bạn có thể sử dụng mô-đun pkg_resources từ setuptools. Ví dụ:

import pkg_resources

package_name = 'cool_package'
try:
    cool_package_dist_info = pkg_resources.get_distribution(package_name)
except pkg_resources.DistributionNotFound:
    print('{} not installed'.format(package_name))
else:
    print(cool_package_dist_info)

Lưu ý rằng có sự khác biệt giữa mô-đun python và gói python. Một gói có thể chứa nhiều mô-đun và tên của mô-đun có thể không khớp với tên gói.



1

Tôi muốn thêm một số suy nghĩ / phát hiện của tôi vào chủ đề này. Tôi đang viết một tập lệnh kiểm tra tất cả các yêu cầu cho một chương trình được tạo tùy chỉnh. Có rất nhiều kiểm tra với các mô-đun python.

Có một vấn đề nhỏ với

try:
   import ..
except:
   ..

giải pháp. Trong trường hợp của tôi, một trong các mô-đun python được gọi python-nmap, nhưng bạn nhập nó với import nmapvà khi bạn thấy tên không khớp. Do đó, thử nghiệm với giải pháp trên trả về kết quả Sai, và nó cũng nhập mô-đun khi đánh, nhưng có thể không cần sử dụng nhiều bộ nhớ để kiểm tra / kiểm tra đơn giản.

Tôi cũng thấy rằng

import pip
installed_packages = pip.get_installed_distributions()

installed_packagessẽ chỉ có các gói đã được cài đặt bằng pip . Trên hệ thống của tôi pip freezetrả về 40các mô-đun python, trong khi installed_packageschỉ có mô-đun 1mà tôi đã cài đặt theo cách thủ công (python-nmap).

Một giải pháp khác bên dưới mà tôi biết nó có thể không liên quan đến câu hỏi , nhưng tôi nghĩ rằng một phương pháp hay là giữ chức năng kiểm tra tách biệt với chức năng thực hiện cài đặt, nó có thể hữu ích cho một số người.

Các giải pháp đã làm việc cho tôi. Nó dựa trên câu trả lời này Cách kiểm tra xem mô-đun python có tồn tại hay không mà không cần nhập nó

from imp import find_module

def checkPythonmod(mod):
    try:
        op = find_module(mod)
        return True
    except ImportError:
        return False

LƯU Ý: giải pháp này cũng không thể tìm thấy mô-đun theo tên python-nmap, tôi phải sử dụng nmapthay thế (dễ sử dụng ) nhưng trong trường hợp này, mô-đun sẽ không được tải vào bộ nhớ.


0

Nếu bạn muốn tập lệnh của mình cài đặt các gói bị thiếu và tiếp tục, bạn có thể làm như sau (ví dụ về mô-đun 'krbV' trong gói 'python-krbV'):

import pip
import sys

for m, pkg in [('krbV', 'python-krbV')]:
    try:
        setattr(sys.modules[__name__], m, __import__(m))
    except ImportError:
        pip.main(['install', pkg])
        setattr(sys.modules[__name__], m, __import__(m))

0

Một cách nhanh chóng là sử dụng công cụ dòng lệnh python . Chỉ cần nhập import <your module name> Bạn sẽ thấy lỗi nếu thiếu mô-đun.

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
>>> import sys
>>> import jocker
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named jocker
$

0

Hmmm ... câu trả lời gần nhất mà tôi thấy là sử dụng dòng lệnh để thử nhập. Nhưng tôi thậm chí muốn tránh điều đó.

Làm thế nào về 'đóng băng pip | grep pkgname '? Tôi đã thử nó và nó hoạt động tốt. Nó cũng cho bạn biết phiên bản mà nó có và liệu nó được cài đặt dưới quyền kiểm soát phiên bản (cài đặt) hay có thể chỉnh sửa (phát triển).


0

class myError (ngoại lệ): vượt qua # hoặc làm một số điều, hãy thử: nhập mymodule ngoại trừ ImportError dưới dạng e: raise myError ("lỗi đã xảy ra")


0

Trong loại thiết bị đầu cuối

pip show some_package_name

Thí dụ

pip show matplotlib

0

Tôi muốn nhận xét để trả lời @ ice.nicer nhưng tôi không thể, vì vậy ... Quan sát của tôi là các gói có dấu gạch ngang được lưu bằng dấu gạch dưới, không chỉ bằng dấu chấm như nhận xét @dwich đã chỉ ra

Ví dụ, bạn làm pip3 install sphinx-rtd-theme, nhưng:

  • importlib.util.find_spec(sphinx_rtd_theme) trả về một đối tượng
  • importlib.util.find_spec(sphinx-rtd-theme) trả về Không có
  • importlib.util.find_spec(sphinx.rtd.theme) tăng ModuleNotFoundError

Hơn nữa, một số tên được thay đổi hoàn toàn. Ví dụ: bạn làm pip3 install pyyamlnhưng nó được lưu đơn giản làyaml

Tôi đang sử dụng python3.8


0
if pip3 list | grep -sE '^some_command\s+[0-9]' >/dev/null
  # installed ...
else
  # not installed ...
fi

-1

Chọn tùy chọn số 2. Nếu ImportErrorđược ném, thì gói đó chưa được cài đặt (hoặc không ở trong sys.path).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.